C++解析(12):初始化列表與物件構造順序
阿新 • • 發佈:2018-12-06
0.目錄
1.類成員的初始化
2.類中的const成員
3.物件的構造順序
- 3.1 區域性物件的構造順序
- 3.2 堆物件的構造順序
- 3.3 全域性物件的構造順序
4.小結
1.類成員的初始化
類中是否可以定義const成員?
下面的類定義是否合法?如果合法,ci的值是什麼,儲存在哪裡?
(會報錯)
C++中提供了初始化列表對成員變數進行初始化
語法規則:
注意事項:
- 成員的初始化順序與成員的宣告順序相同
- 成員的初始化順序與初始化列表中的位置無關
- 初始化列表先於建構函式的函式體執行
證明成員的初始化順序與成員的宣告順序相同,而與初始化列表中的位置無關:
#include <stdio.h> class Value { private: int mi; public: Value(int i) { printf("i = %d\n", i); mi = i; } int getI() { return mi; } }; class Test { private: Value m2; Value m3; Value m1; public: Test() : m1(1), m2(2), m3(3) { printf("Test::Test()\n"); } }; int main() { Test t; return 0; }
執行結果為:
[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out
i = 2
i = 3
i = 1
Test::Test()
2.類中的const成員
類中的const成員:
- 類中的const成員會被分配空間的
- 類中的const成員的本質是隻讀變數
- 類中的const成員只能在初始化列表中指定初始化
編譯器無法直接得到const成員的初始值,因此無法進入符號表成為真正意義上的常量。
證明類中的const成員的本質是隻讀變數:
#include <stdio.h> class Value { private: int mi; public: Value(int i) { printf("i = %d\n", i); mi = i; } int getI() { return mi; } }; class Test { private: const int ci; Value m2; Value m3; Value m1; public: Test() : m1(1), m2(2), m3(3), ci(100) { printf("Test::Test()\n"); } int getCI() { return ci; } int setCI(int v) { int* p = const_cast<int*>(&ci); *p = v; } }; int main() { Test t; printf("t.ci = %d\n", t.getCI()); t.setCI(10); printf("t.ci = %d\n", t.getCI()); return 0; }
執行結果為:
[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out
i = 2
i = 3
i = 1
Test::Test()
t.ci = 100
t.ci = 10
初始化與賦值不同:
- 初始化:對正在建立的物件進行初值設定
- 賦值:對已經存在的物件進行值設定
3.物件的構造順序
3.1 區域性物件的構造順序
對於區域性物件——當程式執行流到達物件的定義語句時進行構造
下面程式中的物件構造順序是什麼?
示例:
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
};
int main()
{
int i = 0;
Test a1 = i;
while( i < 3 )
{
Test a2 = ++i;
}
if( i < 4 )
{
Test a = a1;
}
else
{
Test a(100);
}
return 0;
}
執行結果為:
[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out
Test(int i): 0
Test(int i): 1
Test(int i): 2
Test(int i): 3
Test(const Test& obj): 0
以下程式改變了程式的執行流,有嚴重的bug,但是不同的編譯器有不同的處理結果,有些編譯器不會報錯,一定要注意這種問題!
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
int getMi()
{
return mi;
}
};
int main()
{
int i = 0;
Test a1 = i; // Test(int i): 0
while( i < 3 )
{
Test a2 = ++i; // Test(int i): 1, 2, 3
}
goto End;
Test a(100);
End:
printf("a.mi = %d\n", a.getMi());
return 0;
}
3.2 堆物件的構造順序
對於堆物件:
- 當程式執行流到達new語句時建立物件
- 使用new建立物件將自動觸發建構函式的呼叫
下面程式中的物件構造順序是什麼?
示例:
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i): %d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj): %d\n", mi);
}
int getMi()
{
return mi;
}
};
int main()
{
int i = 0;
Test* a1 = new Test(i); // Test(int i): 0
while( ++i < 10 )
if( i % 2 )
new Test(i); // Test(int i): 1, 3, 5, 7, 9
if( i < 4 )
new Test(*a1);
else
new Test(100); // Test(int i): 100
return 0;
}
執行結果為:
[[email protected] Desktop]# g++ test.cpp
[[email protected] Desktop]# ./a.out
Test(int i): 0
Test(int i): 1
Test(int i): 3
Test(int i): 5
Test(int i): 7
Test(int i): 9
Test(int i): 100
3.3 全域性物件的構造順序
對於全域性物件:
- 物件的構造順序是不確定的
- 不同的編譯器使用不同的規則確定構造順序
(要避開全域性物件之間的相互依賴!)
4.小結
- 類中可以使用初始化列表對成員進行初始化
- 初始化列表先於建構函式體執行
- 類中可以定義const成員變數
- const成員變數必須在初始化列表中指定初值
- const成員變數為只讀變數
- 區域性物件的構造順序依賴於程式的執行流
- 堆物件的構造順序依賴於new的使用順序
- 全域性物件的構造順序是不確定的