C++——構造函數 constructor


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 }
View Code

調試結果

 這里調用了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 }
View Code
 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 }
View Code

這種情況直接編譯不過。錯誤 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 }
View Code

在進行賦值 或 類型轉換的時候,如果要借助構造函數是不允許隱式轉換的。所以第20行必須強制轉換(顯式轉換)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM