一、Big Three:拷貝構造函數,拷貝賦值函數,析構函數
1.拷貝構造函數
文字定義:拷貝構造函數,又稱復制構造函數,是一種特殊的構造函數,它由編譯器調用來完成一些基于同一類的其他對象的構建及初始化。其唯一的形參必須是引用,但并不限制為const,一般普遍的會加上const限制。
形式定義:string(const string& str);
調用形式:string s1("hello");
? ? ? ? ? ? ? ? string s2(s1);//這里調用,在構造階段
? ? ? ? ? ? ? ? string s2 = s1;//和上面完全一樣
2.拷貝賦值函數
文字定義:當兩個對象之間相互賦值的時候調用,使左值對象拷貝一份右值對象的的數據并覆蓋左值對象原來的數據。
形式定義:string operator= (const string& str) ;
調用形式:string s1("hello");
? ? ? ? ? ? ? ? string s2;
? ? ? ? ? ? ? ? s2 = s1;//這里調用,不構造,原對象已經存在
3.析構函數
文字定義:析構函數(destructor) 與構造函數相反,當對象結束其生命周期時(例如對象所在的函數已調用完畢),系統自動執行析構函數。
形式定義:~string();
調用形式:string *s = new string("hello");
? ? ? ? ? ? ? ? delete s;//這里調用
注意:一定要在operator=中檢測自我賦值!!!
二、堆、棧與內存管理
定義:
生命周期:
stack object會在其作用域(scope)結束之際結束,這種作用域內的object,又被稱為auto object,因為它會被自動清理。
static object的生命在作用域結束之后仍然存在,直至程序結束。
global object的生命也是直至程序結束。
heap object的生命是在當它顯示地調用new時,誕生,顯示地調用delete的時候,結束。若調了new卻不調delete,會造成內存泄漏。
關于new:
會經歷:分配內存->強制類型轉換->調用構造函數。
無指針類complex:
有指針類string:
關于delete []:
會經歷:調用析構函數->delete函數釋放該對象本身的空間。一般在析構函數中完成該對象指向的別處的空間。
無指針類complex:
有指針類string:
內存分配塊:
調試模式下:首尾:2個cookie ? ? ? ?調試模式下的占用:32+4 ? ? ? ? 數據:4*2
以上合計52個字節。由于要保持與計算機尋址對齊,這里字符填充為16的倍數,即64個字節。
41中的4就表示64個字節,41中的1表示這片內存被占用著。
其它分析同理。
單獨new:
array new:
調試模式下:首尾:2個cookie ? ? ? ?debugger header占用:32+4? ? ? ? 數據:8*3 ? ??
數組大小指示:4(下面的3)
合計72字節,對齊后變成80字節。51h的5代表80個字節數,1代表這塊空間被占用著。
注意:array new一定要搭配array delete
三、string的實現
四、類模板,函數模板及其它
static:
一個使用static數據成員的例子:銀行利率
單例模式的例子:
另一種寫法:
類模板:
template<typename T>
這里定義一個復數類......
complex<int> c1(2.5, 1.5);
complex<double> c2(2, 5);
函數模板:
namespace std//可能是多個地方糅合到一起的。
{
...
}
其它細節:
五、組合、委托與繼承
1.組合(composition)
定義:在一個類中以另一個類的對象作為數據成員的,稱為類的組合(composition)
替換掉上面默認的模板參數后變成:
一個組合的空間大小分析:
Adapter設計模式:
現在需要的功能已經有完整的實現了,只是名稱和接口不一樣,重新寫一個改造一下就行了。這個就叫改造器(Adapter)。
組合構造析構順序:
組合當中的構造先后順序:由內而外,先構造組合對象,再構造自己。
組合當中的析構先后順序:以外而內,先析構自己,再析構組合對象。
2.委托(delegation):composition by reference
編譯防火墻:
左邊的內容不用變,不用再次編譯,右邊的內容可以變。
注意點:
引用計數(reference counting)
n那里是一塊共享內存,a,b,c不要輕易把控全局。
當a,b,c需要改變內容時,單獨給它拷貝一份,另外兩個繼續共享。這個叫copy on write.
3.繼承(inheritance)
繼承:通過繼承機制,可以利用已有的數據類型來定義新的數據類型。所定義的新的數據類型不僅擁有新定義的成員,而且還同時擁有舊的成員。我們稱已存在的用來派生新類的類為基類,又稱為父類。由已存在的類派生出的新類稱為派生類,又稱為子類。
繼承的三種方式:
公有繼承(public):公有繼承的特點是基類的公有成員和保護成員作為派生類的成員時,它們都保持原有的狀態,而基類的私有成員仍然是私有的,不能被這個派生類的子類所訪問。
在公有繼承時,派生類的對象可以訪問基類中的公有成員;派生類的成員函數可以訪問基類中的公有成員和保護成員。這里,一定要區分清楚派生類的對象和派生類中的成員函數對基類的訪問是不同的。
protect:保護繼承的特點是基類的所有公有成員和保護成員都成為派生類的保護成員,并且只能被它的派生類成員函數或友元訪問,基類的私有成員仍然是私有的。
這種繼承方式與私有繼承方式的情況相同。兩者的區別僅在于對派生類的成員而言,對基類成員有不同的可見性。
private:私有繼承的特點是基類的公有成員和保護成員都作為派生類的私有成員,并且不能被這個派生類的子類所訪問。
在私有繼承時,基類的成員只能由派生類中的成員函數訪問,而且無法再往下繼承。
繼承的構造析構順序:
繼承的構造順序:由內而外,先父類再子類。
繼承的析構順序:由外而內,先子類再父類。
注意:父類的析構函數最好寫成virtual。
六、虛函數和多態
1.虛函數(virtual):
template method設計模式:
寫好固定的部分(Application framework),留出自己實現的部分。