C++回爐之_C++PrimerPlus_第十二章 類和動態記憶體分配
阿新 • • 發佈:2019-02-14
複製建構函式 |
- 如果沒有定義複製建構函式 – C++會自動提供
原型
class_name(const class_name&); Point(const Point&);
- 功能
- 逐個複製非靜態成員的值 – 淺複製
- 如果含有成員的型別也是類, 則使用此成員的複製建構函式來複制此物件
- 當類成員裡含有指標的時候,那麼這兩個物件的此成員都會指向同一個記憶體 – 這很不好
- 此時會使用new初始化指標成員,然後手動定義一個複製建構函式,進行深複製
- 注意要保證所有的建構函式裡new的使用都與解構函式保持一致 – 有時候需要調整預設構造以實現這一點
- 此時會使用new初始化指標成員,然後手動定義一個複製建構函式,進行深複製
何時會呼叫
新建一個物件並將其初始化為同類現有物件時
Point a(b); Point a = b; Point a = Point(b); Point a = new Point(b);
每當程式生成物件副本的時候,都會呼叫複製建構函式
- 函式按值傳遞物件 或 函式返回物件時 – 可按引用傳遞
複製賦值函式 |
- 實質是賦值運算子的過載
- 如果沒有定義, C++會自動提供
初始化類時不一定呼叫賦值運算子, 也可能只調用複製建構函式
初始化總會呼叫複製建構函式,但只是有可能呼叫賦值運算子
Point a = b; // 是否呼叫賦值運算子取決於實現
原型
class_name& class_name::operator=(const
使用
- 同複製構造一樣,當成員函式含有指標的時候,同樣需要手動建立
- 手動建立時需要注意一些事項
- 需要先釋放目標物件之前使用new分配的舊資料
- 應儘量避免將物件賦值給本身 – 否則可能會在賦值前釋放其舊資料
- 應返回一個指向呼叫物件的引用 – 為了可以連續賦值
- 由此可知賦值函式並不建立新的物件
- 可以進一步過載賦值運算子,以支援其他型別到此類的轉換
- 如果目前還沒有必要實現複製構造和賦值運算子,但也不希望有複製或賦值現象發生,可將這兩個函式宣告為private且忽略其實現(將永遠不會被呼叫)
過載[]運算子 |
對於
[]
操作符,兩個運算元一個在[
左邊,一個在[]
operator[](type_name);
a[4]
等價於a.operator[](4);
- 有時候將返回型別宣告為引用,即可使用
[]
對元素(即使是私有成員)進行賦值 當物件為const型別時,便不能使用
[]
進行賦值此時需要宣告一個const版本的
[]
過載版本const return_name& oeprator[](typename) const;
類中的new和delete* |
在類中使用new的注意事項
- 建構函式中使用new, 解構函式中要使用delete
- new對應delete – new[] 對應delete[]
- 如果有多個建構函式,需要以相同的方式使用new – 只有一個解構函式
- 也可以將指標初始化為空 –
0 NULL nullptr(C++11)
– delete可以用於空指標
- 也可以將指標初始化為空 –
應當定義一個複製建構函式,通過深度複製將一個物件初始化為另一個物件
String::String(const String& s) { len = s.len; str = new char[len+1]; // 分配空間 -- 深複製 strcpy(str, s.str); }
應當定義一個賦值運算子,通過深度複製將一個物件複製給另一個物件
String& String::operator=(const String& s) { // 返回引用 -- 防止建立額外副本 if(this == &s) return *this; // 自我賦值時 -- 直接返回this delete[] str; // 清理舊資料 len = s.len; str = new char[len+1]; strcpy(str, s.str); return *this; }
函式的返回物件型別 |
返回指向const物件的引用
- 返回物件將呼叫複製建構函式,而返回引用不會
- 返回引用將提高效率
- 返回的引用不能是所在函式的區域性變數
- const型別引用的返回值也應該是const
返回const型別引用可使函式在呼叫的時候不被修改
const int& Max(int& x, int& y); Max(a, b)++; // 這樣便是不對的, 但如果不是const的話便可以
返回const引用的函式可以賦值給此型別變數(賦值了一下),也可賦值給const型別的引用,但是不能賦值給非const的引用
int c = Max(a, b); // 正確 const int& c = Max(a, b); // 正確 int& c = Max(a, b); // 錯誤
const Point& Max(const Point& a, const Point& b) { if(a.x > b.x) return a; return b; }
返回指向非const物件的引用
- 有時候是為了提高效率 – 如過載賦值運算子
- 也可以返回物件,也可以返回引用 – 返回引用可避免建立新的副本
- 有時候是為了必須這樣做 – 如過載
cout的<<
運算子
- ostream物件沒有公有的複製建構函式
- 有時候是為了提高效率 – 如過載賦值運算子
- 返回物件
- 返回物件是函式中的區域性變數時,只能使用返回物件而非引用 – 如過載+運算子
- 存在複製建構函式建立返回的物件的開銷,但無法避免
- 返回const物件
- 主要是為了防止函式(或過載了操作符的表示式)本身成為左值而導致的一些問題
- 如
a+b = x;
這種式子無意思 且如果用在if()時還有可能出現不易察覺的錯誤
- 如
- 主要是為了防止函式(或過載了操作符的表示式)本身成為左值而導致的一些問題
指向物件的指標 |
Point* p = new Point(1, 2);
cout << p->get_x() << endl;
delete p;
定位new運算子不能用delete釋放 – 可顯示呼叫解構函式
char* buffer = new buffer[maxn]; Point* p1 = new(buffer) Point; Point* p2 = new(buffer + sizeof(Point)) Point(1, 2); p2->~Point(); p3->~Point(); delete[] buffer;