在編寫C++程序的時候,我們會為特定某一類對象申明類類型,幾乎我們申明的每一個class都會有一個或多個構造函數、一個析構函數、一個賦值運算符重載=、以及拷貝構造函數。這些函數控制著類對象的基礎操作,確保新定義的對象的初始化、完成對象撤銷時的清理工作、賦予對象新值。如果這些函數的操作出錯,則會導致嚴重的後果,所以確保這些函數的操作行為正常是非常重要的。
一、編譯器默認生成的函數
如果我們編寫一個空類,編譯器會為我們默認生成構造函數、析構函數、賦值運算符、拷貝構造函數。
例如當我們定義
class Empty{ };
就好像我們寫下了如下代碼(紅色是編譯器默認生成)
class Empty{
public:
Empty(){....} //默認構造函數
Empty(const Empty &rhs){....} //默認拷貝構造函數
~Empty(){....} //默認析構構造函數
Empty& operator=(const Empty &rhs){....} //賦值運算符
Empty* operator&(){...} //取地址運算符
const Empty* operator&() const{...} //取地址運算法的const版本
};
1. 說明:(1)這些函數只有在被調用的時候,才會被編譯器創建出來;
(2)四個函數都public且inline的;
(3)如果顯示的定義了其中某一個函數,那麼編譯器就不會生成其對應的默認的版本;
(4)自定義的拷貝構造函數不僅會覆蓋默認的拷貝構造函數,同時也會覆蓋默認的構造函數,下面的函數class構造函數,不能通過編譯
1 class Empty 2 { 3 4 public: 5 Empty(const Empty& e) {} 6 }; 7 8 int main(int argc, char** argv) 9 { 10 Empty a; 11 } 12 // error: no matching function for call to 'Empty::Empty()'| View Code
2. 實例:
下面的代碼會讓編譯器創建默認的構造函數 Empty e1; //默認構造函數
Empty e2(e1);//拷貝構造函數
e2 = e1;//賦值運算符
1 #include <iostream> 2 using namespace std; 3 4 class Empty{ 5 6 public: 7 Empty(){cout << "create" << endl;} 8 Empty(const Empty &Copy){ cout << "copy" << endl;} 9 Empty& operator=(const Empty &Assig){cout << "assign=" << 10 endl;} 11 Empty* operator&(){cout << "&" << endl;} 12 const Empty* operator&() const {cout << "&1" << endl;} 13 ~Empty(){cout << "delete" << endl;} 14 }; 15 int main() 16 { 17 Empty *e = new Empty(); // create 18 delete e; //delete 19 Empty e0; //create 20 const Empty e1; //create 21 Empty e2(e1); //copy 22 Empty e3; //create 23 e3 = e1;//assign= 24 cout << &e0 << endl;//& 0x602080 25 const Empty *p = &e1;//&1 26 cout << p << endl; //0x602080 27 return 0; 28 } 29 //e0,e1,e2,e3對象被撤銷時候刪除 30 delete 31 delete 32 delete 33 delete View Code
二、構造函數
1. 構造函數的作用
構造函數是特殊的成員函數,用來在創建對象時完成對對象屬性的一些初始化等操作, 當創建對象時, 對象會自動調用它的構造函數。
2. 默認構造函數
正如第一部分所述,如果沒有為一個類顯示定義任何構造函數、編譯器將自動為這個類生成默認構造函數。默認構造函數將依據變量初始化的規則初始化類中的所有成員:
(1)對於具有類類型的成員,會調用該成員所屬類自身的默認構造函數實現初始化;
(2)內置類型成員的初值依賴於對象如何定義,如果對象在全局作用域中定義或定義為靜態局部對象,則這些成員將被初始化為0。如果對象在局部作用域中定義,則這些成員沒有初始化;
(3)默認構造函數一般適用於僅包含類類型的成員的類;
(4)由於默認構造函數不會初始化內置類型的成員,所以必須顯示定義類的構造函數。
1 #include <iostream> 2 using namespace std; 3 class Empty 4 { 5 public: 6 int a; 7 string s; 8 }; 9 10 int main(int argc, char** argv) 11 { 12 Empty a; 13 cout << a.a << endl;//輸出a的值隨機 14 cout << a.s.size() << endl;//s是類類型被初始化為空串 15 } View Code3. 構造函數的特點
(1)在對象被創建時自動執行;
(2)構造函數的函數名與類名相同;
(3)沒有返回值類型、也沒有返回值;
(4)構造函數不能被顯式調用;
4. 重載構造函數
可以為一個類申明的構造函數的數量沒有限制,只要每個構造函數的形參表示唯一的。定義類對象的時候,實參指定使用哪個構造函數。