1. 程式人生 > >C++建構函式介紹

C++建構函式介紹

建構函式定義:

每個類都分別定義了它的物件被初始化的方式,類通過一個或幾個特殊的成員函式來控制其物件的初始化過程,這些函式叫做建構函式。

從定義中,首先可以得知以下兩點:

  1. 建構函式也是一種類的成員函式,但是其有特殊性。
  2. 任務是初始化類物件的資料成員,所以無論何時只要類物件被建立,就會執行建構函式。

建構函式與普通成員函式的區別:

  1. 建構函式沒有返回型別
  2. 建構函式的函式名需要與類名一致
  3. 建構函式不是由物件呼叫的,而建構函式一般物件建立時系統自動執行建構函式,當然也可以顯示呼叫建構函式,這裡言外之意就是建構函式不能被外部呼叫。
  4. 建構函式是一個類必須有的,若沒有定義建構函式,編譯器在程式需要時會建立一個預設的建構函式

 分析上述中的第3、4點:顯示呼叫建構函式和預設建構函式

  1 #include<stdio.h>
  2 //A.h
  3 class A
  4 {
  5 
  6 public:
  7     A() = default;
  8     A(int x);
  9     ~A();
 10 };
 11 
 12 //A.cpp
 13 A::A()
 14 {
 15     printf("This is the default constructor!\n");
 16 }
 17 
 18 A::A(int x)
 19 {
 20     printf("This is the customize constructor!\n");
 21 }
 22 
 23 A::~A()
 24 {
 25     printf("This is the destructor!\n");
 26 }
 27 
 28 
 29 int main()
 30 {
 31     A test; //do the A() construct function
 32     test = A(10);
 33 
 34     return 0;
 35 }

輸出結果:

This is the default constructor!
This is the customize constructor!
This is the destructor!
This is the destructor!

分析:這段程式碼很有意思,首先建立一個物件test,然後系統呼叫預設建構函式A()。那什麼叫預設建構函式呢?

 

預設建構函式定義:

預設建構函式就是在呼叫時不需要顯示地傳入實參的建構函式

若類沒有建構函式時,編譯器會制度牌沒提供一個預設建構函式。當然一個類,不能有兩個預設建構函式。

所以以下兩個預設建構函式是不能同時存在的。

  1 class A
  2 {
  3     A() = default;  //預設建構函式
  4     A(int i = 5);   //預設建構函式
  5 };
  6 
  7 A::A(int i)
  8 {
  9 
 10 }
 11 
 12 int main()
 13 {
 14     A test;
 15     return 0;
 16 }

編譯後,會發現報錯。 其實從過載就可以解釋,系統不知道該呼叫哪個預設建構函式。

 

程式自己定義的建構函式就不用多解釋了(其實一般寫程式都自己加上的),但是如果沒有建構函式,則物件建立的時候,編譯器會自動生成一個預設建構函式。那麼這個編譯器生成的預設建構函式有什麼用呢?

 

 

預設建構函式作用1-無用建構函式

只是為了滿足程式能執行,並不幹其他事情,如初始化資料成員。見下面程式碼:

  1 #include<stdio.h>
  2 class A
  3 {
  4 public:
  5     int m_num;
  6 };
  7 
  8 
  9 int main()
 10 {
 11     A test;
 12     printf("m_num=%d\n",test.m_num);
 13     return 0;
 14 }



/////以上程式碼等同於
class A
{
public:
    A() = default;
    int m_num;
};

輸出結果為:m_num=-1031285632

從結果可以看出,雖然編譯器會提供一個預設建構函式,但是這個建構函式沒有做任何事情,這與我們定義了一個空的預設建構函式作用一樣。

但是為什麼編譯器生成的預設建構函式沒有初始化變數m_num,這裡有個規則:

定義在塊中的內建型別或複合型別(比如陣列和指標)的物件被預設初始化,則它們的值將是未定義的。因此,含有內建型別或複合型別成員的類應該在類的內部初始化這些成員,或者定義一個自己的預設建構函式。否則,使用者在建立類的物件時就可能得到未定義的值。

對於無用的預設建構函式,我看過一些部落格,他們認為這種無用的預設建構函式不能算建構函式,因為如果用vs編譯上述程式碼壓根就編譯不了,vs給的錯誤提示是區域性變數test未初始化。但是我還是理解只要沒有顯示提供建構函式,編譯器就會生成一個預設建構函式,不管有用還是沒用。

以上僅個人在當前的意見!不一定對!

 

預設建構函式作用2-有用建構函式

一般上,當編譯器被需要時才生成有用的建構函式,分為以下4個情形:

  1. 當該類的類物件資料成員有預設建構函式時。

  2. 當該類的基類有預設建構函式時。

  3. 當該類的基類為虛基類時。

  4. 當該類有虛擬函式時。

這部分可以參考部落格:https://www.cnblogs.com/QG-whz/p/4676481.html

預設建構函式分析就到此。

 

顯示呼叫建構函式

之前程式碼中有

A test; 
test = A(10);

從字面上似乎可以這樣理解,先建立一個物件test,然後顯示呼叫建構函式A(int x),在將一個東西賦值給test,因為test是個物件,那麼這個東西也應該是物件。

這裡有兩個知識點:

(1)無名物件

(2)賦值建構函式

(3)explicit關鍵字:這個是隱藏知識點,這裡不介紹了。

首先A(10)產生一個無名物件,然後通過賦值建構函式(上述程式碼編譯器預設提供了operator =),賦值給test物件,然後這個無名物件銷燬,呼叫解構函式。

 

無名物件:也叫臨時物件。指的是直接由建構函式產生,但是沒有被任何符號所引用的物件。例如:string("abc"),這句話產生的就是一個無名物件,這個物件產生以後,沒有什麼辦法使用它。但是對於string str("abc")來說,則產生的是一個有名字的物件,他的名字就是 str。

無名物件的用法這裡不深入探討了。

 

賦值建構函式和拷貝建構函式,這裡就不介紹了,下次單獨再寫。

還有建構函式初始化問題。

再一次感受到C++的魅力!