What is constructor
- C++中,如果你想要創建一個object,有一個函數會自動被調用(不需要programmer顯式調用 ),這個函數就是constructor;
- constructor的寫法很獨特,其function name必須和class name相同;
- constructor通過arguments上的差異進而形成ctor的overloading,當然和normal function一樣,ctor也可以有default arguments;
- ctor沒有返回值類型;
- ctor還有個特色功能(ctor獨享),initialization list(初始化列表)。與在{ ... }內部賦值private data,initialization list速度會更快。簡單講,一個variable數值的設定有2個階段,分別是initialization和assignment,initialization先於assignment階段進行。initialization list就是發生在initialization階段,{ ... }內部賦值private data屬於assignment階段。如果不使用initialization list表明你主動放棄initialization階段工作,雖然最后你還是把數值放入到variable,但是時間晚了些,效率差了些;
默認實參,構造函數,普通函數都有這種性質。
ctor's overloading
參考:C++——overloading principle analysis
關於header file、static、inline、variable hides的一點感想
我們知道C不允許overloading,C++允許overloading。C++在編譯器一側時別到的函數名與我們看到的函數名是有很大差異的。normal function和ctor的overloading方式差不多。下圖事normal function的重載。
注意:黃色部分①②兩個ctor則不可以同時存在,①對於的ctor所有形參都有默認參數,這時候就相當於default ctor,和②是一樣的效果。編譯器在這種情況下無法做出選擇。雖然這也是overloading,但是這種overloading讓compiler困惑
常量成員函數
在函數后頭加const,表示函數不會改變調用者的內容,或 形參在函數內部不會改變。
如果忘記加const,右下角的例子,c1是個常量,而real和imag卻有可能改變c1,產生矛盾,編譯器報錯。
singleton——把構造函數放在private區
design patrern中 的一種模式
構造函數的作用
①構造對象:在用類定義一個對象時會自動調用構造函數
②初始化對象:類的數據成員往往放在構造函數里面初始化
③類型轉換:看講解
無論C 、C++都是強類型語言,不同類型變量之間不能隨便賦值。很多時候我們認為理所當然的賦值都是借助臨時變量來實現的。看代碼

1 #include<iostream> 2 class Test { 3 public: 4 Test(int a=0) 5 { 6 std::cout << "Create Test Object:" << this<<std::endl; 7 this->a = a; 8 } 9 ~Test() 10 { 11 std::cout << "Free Test Object:" << this << std::endl; 12 } 13 private: 14 int a; 15 }; 16 17 int main(int argc, char **argv) 18 { 19 Test t1; 20 t1 = 100; 21 getchar(); 22 return 0; 23 }
調試結果
這里調用了2此構造函數,2次析構函數(析構順序是棧操作順序)。輸出結果解析
第1行輸出:執行第19行,調用構造函數
第2行輸出:執行第20行,調用構造函數。這里創建了一個臨時Test類型對象(C++為了凸顯逼格把類類型的變量稱為對象),100就是傳入構造函數的參數。
第3行輸出:第2行構造完臨時對象后,賦值給了對象t1。賦值以后臨時對象的生命期就結束了,這里調用析構函數,終結這個臨時對象
第4行輸出:第22行return 0返回后調用析構函數,終結對象t1
畫圖解釋這一過程
這里面最關鍵的一個環節就是int類型到Test臨時對象轉換,int類型要找到一個途徑來轉換成Test類型。這個途徑是什么呢? 構造函數
而我們代碼里面恰恰有這么個構造函數,他的參數就是一個整形。如果我們干掉這個構造函數,換一個不帶參數的構造函數(或者干脆不寫構造函數,使用默認的),則不能將100賦值給t1
代碼如下

1 #include<iostream> 2 class Test { 3 public: 4 Test() 5 { 6 std::cout << "Create Test Object:" << this << std::endl; 7 this->a = a; 8 } 9 ~Test() 10 { 11 std::cout << "Free Test Object:" << this << std::endl; 12 } 13 private: 14 int a; 15 }; 16 17 int main(int argc, char **argv) 18 { 19 Test t1; 20 t1 = 100; 21 getchar(); 22 return 0; 23 }

1 #include<iostream> 2 class Test { 3 public: 4 ~Test() 5 { 6 std::cout << "Free Test Object:" << this << std::endl; 7 } 8 private: 9 int a; 10 }; 11 12 int main(int argc, char **argv) 13 { 14 Test t1; 15 t1 = 100; 16 getchar(); 17 return 0; 18 }
這種情況直接編譯不過。錯誤 C2679 二進制“ = ”: 沒有找到接受“int”類型的右操作數的運算符(或沒有可接受的轉換)。在類型轉換的時候,編譯器試圖尋找能實現轉換的構造函數,能找到就執行構造函數生成一個臨時對象好用於賦值。找不到就報錯。
額外補充:對於隱式類型轉換,生成的臨時對象具有const性質。參考 C++——引用
explicit關鍵字
有的時候我們會發現構造函數前面加了個關鍵字explicit,代碼如下

1 #include<iostream> 2 class Test { 3 public: 4 explicit Test(int a = 0) 5 { 6 std::cout << "Create Test Object:" << this << std::endl; 7 this->a = a; 8 } 9 ~Test() 10 { 11 std::cout << "Free Test Object:" << this << std::endl; 12 } 13 private: 14 int a; 15 }; 16 17 int main(int argc, char **argv) 18 { 19 Test t1; 20 t1 = (Test)100; 21 getchar(); 22 return 0; 23 }
在進行賦值 或 類型轉換的時候,如果要借助構造函數是不允許隱式轉換的。所以第20行必須強制轉換(顯式轉換)。