類(lèi)和動(dòng)態(tài)內(nèi)存分配
1. 動(dòng)態(tài)內(nèi)存和類(lèi)
靜態(tài)成員
- 注意: 靜態(tài)數(shù)據(jù)成員在類(lèi)中聲明,在類(lèi)外初始化, 但如果靜態(tài)成員是const整數(shù)類(lèi)型或枚舉型可以在類(lèi)聲明中初始化
- 靜態(tài)成員初始化時(shí)不加static限定符, 否則會(huì)將其作用域局限在所在的文件
new和delete
- 構(gòu)造函數(shù)使用new分配內(nèi)存時(shí), 必須在相應(yīng)的析構(gòu)函數(shù)中delete來(lái)釋放, 如果使用new [ ]來(lái)分配內(nèi)存,則應(yīng)使用delete [ ]來(lái)釋放
- 如果有多個(gè)構(gòu)造函數(shù), 則必須以相同的方式使用new, 要么都帶中括號(hào), 要么都不帶
特殊成員函數(shù)
- C++自動(dòng)提供以下函數(shù):
- 默認(rèn)構(gòu)造函數(shù), 如果沒(méi)有定義任何構(gòu)造函數(shù)
- 默認(rèn)析構(gòu)函數(shù), 如果沒(méi)有定義
- 默認(rèn)拷貝構(gòu)造函數(shù), 如果沒(méi)有定義
- 賦值運(yùn)算符重載, 如果沒(méi)有定義
- 地址運(yùn)算符重載, 如果沒(méi)有定義
- C++11 還提供了移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值函數(shù)
- 警告: 當(dāng)類(lèi)中包含了使用new初始化的指針成員, 應(yīng)當(dāng)定義一個(gè)拷貝構(gòu)造函數(shù), 用來(lái)復(fù)制數(shù)據(jù)而不是簡(jiǎn)單的指針復(fù)制.
- 賦值運(yùn)算符
C++允許類(lèi)對(duì)象賦值, 就是通過(guò)自動(dòng)為類(lèi)重載賦值運(yùn)算符實(shí)現(xiàn)的
將已有的對(duì)象賦給另一個(gè)對(duì)象時(shí), 將使用重載的賦值運(yùn)算符
使用已有對(duì)象初始化另一對(duì)象時(shí), 可能會(huì)使用賦值運(yùn)算符
2. String類(lèi)
- 函數(shù)成員使用new動(dòng)態(tài)分配, 應(yīng)提供拷貝構(gòu)造函數(shù)和重載賦值運(yùn)算
- String類(lèi)簡(jiǎn)單實(shí)現(xiàn)代碼:
/*
* String.h
*/
#ifndef CPLUSPLUS_STRING_H
#define CPLUSPLUS_STRING_H
#include <iostream>
#include <cstring>
using namespace std;
class String {
public:
String(); // 默認(rèn)構(gòu)造函數(shù)
String(const char* str); // 普通構(gòu)造函數(shù)
String(const String& s); // 拷貝構(gòu)造函數(shù)
~String(); // 析構(gòu)函數(shù)
String &operator=(const String& s); // 重載賦值運(yùn)算
String &operator=(const char* str); // 重載賦值運(yùn)算
friend ostream &operator<<(ostream& os, const String& s);
private:
char* m_str;
size_t length;
};
#endif //CPLUSPLUS_STRING_H
/*
* String.cpp
*/
#include "String.h"
String::String(const char* str) {
length = std::strlen(str);
m_str = new char[length + 1];
strcpy(m_str, str);
}
String::String() {
length = 0;
m_str = nullptr;
}
String::String(const String& s) {
length = s.length;
m_str = new char[length + 1];
strcpy(m_str, s.m_str);
}
String::~String() {
delete [] m_str;
m_str = nullptr;
}
String &String::operator=(const String &s) {
if (this == &s) { // 檢查是否為自身賦值
return *this;
}
delete [] m_str;
length = s.length;
m_str = new char[length + 1];
strcpy(m_str, s.m_str);
return *this;
}
String &String::operator=(const char *str) {
delete [] m_str;
length = strlen(str);
m_str = new char[length + 1];
strcpy(m_str, str);
return *this;
}
ostream &operator<<(ostream &os, const String &s) {
os << s.m_str;
return os;
}
- C++11 提供了關(guān)鍵字nullptr來(lái)表示空指針, 盡量使用nullptr而不是0或者NULL
- 包含類(lèi)成員的類(lèi)的賦值或拷貝時(shí)會(huì)調(diào)用類(lèi)成員自身的賦值運(yùn)算或拷貝構(gòu)造函數(shù)
3. 定位new運(yùn)算符
- 定位new運(yùn)算符用于為類(lèi)對(duì)象分配空間時(shí),需要顯式調(diào)用類(lèi)的析構(gòu)函數(shù)(如果需要析構(gòu)的話(huà))
char *buffer = new char[1024];
String* pn = new (buffer) String;
pn->~String(); // 顯示調(diào)用析構(gòu)函數(shù)
delete [] buffer; // 釋放new的空間
// 直接使用對(duì)象指針釋放是錯(cuò)誤的
delete pn; // 錯(cuò)誤, 不能釋放buffer且不會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)
4. 成員初始化列表
- 只能用于構(gòu)造函數(shù)
- 必須用這種格式來(lái)初始化非靜態(tài)const類(lèi)型數(shù)據(jù)成員
- 必須用這種方法來(lái)初始化引用數(shù)據(jù)成員
- 數(shù)據(jù)成員初始化的順序與初始化器中的順序無(wú)關(guān), 和成員的聲明順序一致
- C++11 允許直接在類(lèi)內(nèi)聲明時(shí)初始化成員