十四、構造函數和初始化表
… …
4、拷貝構造函數
1)用一個已經存在的對象構造同類型的副本對象,會調用拷貝構造函數;
語法:
類名(const 類型& that){//完成成員的拷貝}
2)如果一個類沒有定義拷貝構造函數,那麼編譯器會爲其提供一個缺省的拷貝構造函數;
- 對於基本類型的成員變量,按字節複製;
- 對於類類型的成員變量,調用相應類拷貝構造函數來初始化;
class A{
};
class B{
int m_data;
A m_a;
};
B b;
B b2(b);
注意:
一般不需要自己定義拷貝構造函數,因爲編譯器提供的缺省拷貝構造函數已經很好用了。
3)拷貝構造函數調用時機
- 用已定義的對象作爲同類型對象的構造實參;
- 以對象形式向函數傳遞參數;
- 從函數中返回對象;
class A{..};
void func(A a){
A a;
return a;
}
int main(){
A a2;
func(a2);
}
5、初始化表
1)用於指明類中成員變量的初始化方式
class 類名{
類名(形參表):成員變量1(初值),..{ //函數體 }
};
eg:
class A{
public:
A(void):m_i(0), m_j(0){
//m_j = 0;
//m_i = 0;
}
A(int i, int j):m_i(i), m_j(j){}
int m_i;
int m_j;
};
2)需要使用初始化表的場景
- 如果類中包含
"const"
或者"引用&"
成員變量,必須在初始化表中進行初始化; - 如果有類類型的成員變量,而該類又沒有無參構造函數,則必須通過初始化表指明構造實參;
注意:
成員變量的初始化順序由聲明順序所決定,而與初始化表的順序無關。
練習:
重構時鐘類,如果以日曆作爲構造實參,則表現爲時鐘功能,如果以無參方式則表現爲計時器。
要求:使用初始化表
十五、this指針與常成員函數
1、this指針
1)類的構造函數和成員函數都有一個隱藏的該類 類型的指針參數,名爲"this"
;
- 對於普通成員函數,this指針就是指向調用該函數的對象;
- 對於構造函數,this指針就是指向正在被構造的對象;
注意:
類中成員函數和構造函數訪問類中其它成員,實際上都是通過this指針完成的。
2)需要顯式使用this指針的場景
- 區分作用域;
- 從成員中返回調用對象的自身;
- 從類的內部銷燬對象的自身;
2、常成員函數(常函數)
1)在一個成員函數參數表後面加上const關鍵字,表示這個函數爲常成員函數。
返回類型 函數名(形參表)const{//函數體}
2)常成員函數中this指針是一個常指針,不能在常成員函數中修改成員變量的值;
注意:
被mutable(adj.易變的/ ‘mju:tәbl /)關鍵字修飾的成員變量可以在常函數中被修改。
3)非 常對象既可以調用非 常函數,也可以調用常函數;而常對象只能調用常函數,不能調用非 常函數。
4)函數名和形參表相同的成員函數,其常版本和非 常版本可以構成重載關係,常對象調用常版本,非 常對象調用非 常版本;
十六、析構函數(Destructor)
1、語法
class 類名{
public:
~類名(void){
//主要用於清理對象創建時分配的動態資源
}
};
1)函數名必須是”~類名”;
2)析構函數沒有參數,也沒有返回類型;
3)析構函數不能重載;
2、當對象被銷燬時,該類的析構函數將被自動執行
1)棧對象當其離開作用域時,其析構函數被作用域右花括號"}"
所調用;
2)堆對象的析構函數被delete運算符調用;
3、如果一個類沒有定義析構函數,那麼編譯器會爲其提供一個缺省的析構函數:
- 對基本類型的成員變量什麼也不做;
- 對類 類型的成員變量,會調用相應類型的析構函數,析構成員子對象;
4、對象的創建和銷燬的過程
1)對象的創建
- 內存分配;
- 構造成員子對象;
- 執行構造函數代碼;
2)對象的銷燬
- 執行析構函數代碼;
- 析構成員子對象;
- 釋放內存;