Part4 類與對象 4.3構造函數
構造函數的作用:在對象被創建時使用特定的值構造對象,將對象初始化為一個特定的初始狀態。
構造函數的形式:
函數名與類名相同;
不能定義返回值類型,也不能有return語句;
可以是內聯函數。
默認構造函數:調用時可以不需要實參的構造函數
1 參數表為空的構造函數
2 全部參數都有默認值的構造函數
下面兩個都是默認構造函數,如在類中同時出現,將產生編譯錯誤:
Clock(); Clock(int newH=0,int newM=0,int newS=0);
隱含生成的構造函數:如果程序中未定義構造函數,編譯器將在需要時自動生成一個默認構造函數
參數列表為空,不為數據成員設置初始值;
如果類內定義了成員的初始值,則使用內類定義的初始值;
如果沒有定義類內的初始值,則以默認方式初始化;
基本類型的數據默認初始化的值是不確定的。
如果程序中已定義構造函數,默認情況下編譯器就不再隱含生成默認構造函數。
如果此時依然希望編譯器隱含生成默認構造函數,可以使用“=default”。
class Clock { public: Clock() = default; //指示編譯器提供默認構造函數 Clock(int newH, int newM, int newS); //構造函數 private: int hour, minute, second; };
//4-2 4-1修改版 #include<iostream> using namespace std; class Clock{ public: Clock(int newH, int newM, int newS);//加入構造函數 void setTime(int newH = 0, int newM = 0, int newS = 0); void showTime(); private: int hour, minute, second; }; //構造函數的實現 Clock::Clock(int newH, int newM, int newS):hour(newH),minute(newM),second(newS){}//參數括號後大括號之前是初始化列表,比在函數體中寫賦值表達式效率高 void Clock::setTime(intnewH, int newM, int newS){ hour = newH; minute = newM; second = newS; } void Clock::showTime(){ cout << hour << ":" << minute << ":" << second; } //對象的使用 int main(){ Clock c(0,0,0); c.showTime(); return 0; }
//4-3 加入默認構造函數 #include<iostream> using namespace std; class Clock{ public: Clock(int newH, int newM, int newS);//加入構造函數 Clock(); //默認構造函數 void setTime(int newH = 0, int newM = 0, int newS = 0); void showTime(); private: int hour, minute, second; }; Clock::Clock(): hour(0),minute(0),second(0) { }//默認構造函數,初始化列表中用自己約定的值,沒有參數傳進來 Clock::Clock(int newH, int newM, int newS):hour(newH),minute(newM),second(newS){}//參數括號後大括號之前是初始化列表,比在函數體中寫賦值表達式效率高 void Clock::setTime(int newH, int newM, int newS){ hour = newH; minute = newM; second = newS; } void Clock::showTime(){ cout << hour << ":" << minute << ":" << second; } //對象的使用 int main(){ Clock c1(1,1,1); Clock c2; c1.showTime(); c2.showTime(); return 0; }
委托構造函數:類中往往有多個構造函數,只是參數表和初始化列表不同,其初始化算法都是相同的,這時,為了避免代碼重復,可以使用委托構造函數。
之前Clock類的兩個構造函數:
Clock(int newH, int newM, int newS) : hour(newH),minute(newM), second(newS) { } //構造函數 Clock::Clock(): hour(0),minute(0),second(0) { }//默認構造函數
委托構造函數使用類的其他構造函數執行初始化過程:
Clock(int newH, int newM, int newS): hour(newH),minute(newM), second(newS){} Clock(): Clock(0, 0, 0) { }//無參的構造函數直接調用有參的構造函數
復制構造函數:是一種特殊的構造函數,其形參為本類的對象引用。作用是用一個已存在的對象去初始化同類型的新對象。
class 類名 { public: 類名(形參);//構造函數 類名(const 類名 &對象名);//復制構造函數,常引用,只能讀,不能改傳進來的那個對象的數據 // ... }; 類名::類(const 類名 &對象名)//復制構造函數的實現 { 函數體 }
復制構造函數被調用的三種情況:
1 定義一個對象時,以本類另一個對象作為初始值,發生復制構造;
2 如果函數的形參是類的對象,調用函數時,將使用實參對象初始化形參對象,發生復制構造;
3 如果函數的返回值是類的對象,函數執行完成返回主調函數時,將使用return語句中的對象初始化一個臨時無名對象,傳遞給主調函數,此時發生復制構造。
隱含的復制構造函數:如果沒有為類聲明拷貝初始化構造函數,則編譯器自己生成一個隱含的復制構造函數。
這個構造函數執行的功能是:用作為初始值的對象的每個數據成員的值,初始化將要建立的對象的對應數據成員。
如果不希望對象被復制構造:
1 C++98 做法:將復制構造函數聲明為private,並且不提供函數的實現。
2 C++11 做法:用“=delete”指示編譯器不生成默認復制構造函數。
class Point { //Point 類的定義 public: Point(int xx=0, int yy=0) { x = xx; y = yy; } //構造函數,內聯 Point(const Point& p) = delete; //指示編譯器不生成默認復制構造函數 private: int x, y; //私有數據 }; int main(){ Point a; Point b(a); //情況一:用a初始化b,調用復制構造函數 cout << b.getX() << endl; fun1(b); //情況二:對象b作為fun1的實參,調用復制構造函數 b = fun2(); //情況三:函數返回值是類對象,函數返回時,調用復制構造函數 cout << b.getX() << endl; return 0; }
Part4 類與對象 4.3構造函數