建構函式在物件生成時會被呼叫,解構函式在物件消亡時會被呼叫。物件何時生成和消亡是由物件的生存期決定的。下面通過一個例子來加深對建構函式、解構函式和變數的生存期的理解。
#include <iostream >
using namespace std;
class Demo {
int id;
public:
Demo(int i)
{
id = i;
cout << "id=" << id << "constructed" << endl;
}
~Demo()
{
cout << "id=" << id << "destructed" << endl;
}
};
Demo d1(1);
void Func()
{
static Demo d2(2);
Demo d3(3);
cout << "func" << endl;
}
int main()
{
Demo d4(4);
d4 = 6;
cout << "main" << endl;
{
Demo d5(5);
}
Func();
cout << "main ends" << endl;
return 0;
}
執行結果(行號只是為了便於檢視,它不是輸出的一部分):
01) id=1constructed
02) id=4constructed
03) id=6constructed
04) id=6destructed
05) main
06) id=5constructed
07) id=5destructed
08) id=2constructed
09) id=3constructed
10) func
11) id=3destructed
12) main ends
13) id=6destructed
14) id=2destructed
15) id=1destructed
要分析程式的輸出,首先要看有沒有全域性物件。因為全域性物件是進入 main 函數以前就形成的,所以全域性物件在 main 函數開始執行前就會被初始化。
本程式第 16 行定義了全域性物件 d1,因此 d1 初始化引發的建構函式呼叫,導致了第 1) 行的輸出結果。
main 函數開始執行後,區域性物件 d4 初始化,導致第 2) 行輸出。
第 26 行,
d4=6;
,6 先被自動轉換成一個臨時物件。這個臨時物件的初始化導致第 3) 行輸出。臨時物件的值被賦給 d4 後,這條語句執行完畢,臨時物件消亡,因此引發解構函式呼叫,導致第 4) 行輸出。
第 29 行的 d5 初始化導致第 6) 行輸出。d5 的作用域和生存期都只到離它最近的,且將其包含在內的那一對
{}
中的
}
為止,即第 30 行的
}
,因此程式執行到第 30 行時 d5 消亡,引發解構函式呼叫,輸出第 7) 行。
第 8) 行的輸出是由於進入 Func 函數後,執行第 19 行的靜態區域性物件 d2 初始化導致的。
靜態區域性物件在函數第一次被呼叫並執行到定義它的語句時初始化,生存期一直持續到整個程式結束,所以即便 Func 函數呼叫結束,d2 也不會消亡。
Func 函數中的 d3 初始化導致了第 9) 行輸出。
第 31 行,Func 函數呼叫結朿後,d3 消亡導致第 11) 行輸出。
main 函數結束時,其區域性變數 d4 消亡,導致第 13) 行輸出。
整個程式結束時,全域性物件 d1 和靜態區域性物件 d2 消亡,導致最後兩行輸出。