C++建構函式介紹
建構函式定義:
每個類都分別定義了它的物件被初始化的方式,類通過一個或幾個特殊的成員函式來控制其物件的初始化過程,這些函式叫做建構函式。
從定義中,首先可以得知以下兩點:
- 建構函式也是一種類的成員函式,但是其有特殊性。
- 任務是初始化類物件的資料成員,所以無論何時只要類物件被建立,就會執行建構函式。
建構函式與普通成員函式的區別:
- 建構函式沒有返回型別
- 建構函式的函式名需要與類名一致
- 建構函式不是由物件呼叫的,而建構函式一般物件建立時系統自動執行建構函式,當然也可以顯示呼叫建構函式,這裡言外之意就是建構函式不能被外部呼叫。
- 建構函式是一個類必須有的,若沒有定義建構函式,編譯器在程式需要時會建立一個預設的建構函式
分析上述中的第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個情形:
-
當該類的類物件資料成員有預設建構函式時。
-
當該類的基類有預設建構函式時。
-
當該類的基類為虛基類時。
-
當該類有虛擬函式時。
這部分可以參考部落格: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++的魅力!