9.2 建構函式的初始化表
建構函式有個特殊的初始化方式叫“初始設定式表”(簡稱初始化表)。初始化表位於函數參數表之後,卻在函數體 {} 之前。這說明該表裡的初始化工作發生在函數體內的任何代碼被執行之前。
建構函式初始化表的使用規則:
u 如果類存在繼承關係,衍生類別必須在其初始化表裡調用基類的建構函式。
例如
class A
{…
A(int x); // A的建構函式
};
class B : public A
{…
B(int x, int y);// B的建構函式
};
B::B(int x, int y)
: A(x) // 在初始化表裡調用A的建構函式
{
…
}
u 類的const常量只能在初始化表裡被初始化,因為它不能在函數體內用賦值的方式來初始化(參見5.4節)。
u 類的資料成員的初始化可以採用初始化表或函數體內賦值兩種方式,這兩種方式的效率不完全相同。
非內部資料類型的成員對象應當採用第一種方式初始化,以擷取更高的效率。例如
class A
{…
A(void); // 無參數建構函式
A(const A &other); // 拷貝建構函式
A & operate =( const A &other); // 賦值函數
};
class B
{
public:
B(const A &a); // B的建構函式
private:
A m_a; // 成員對象
};
樣本9-2(a)中,類B的建構函式在其初始化表裡調用了類A的拷貝建構函式,從而將成員對象m_a初始化。
樣本9-2 (b)中,類B的建構函式在函數體內用賦值的方式將成員對象m_a初始化。我們看到的只是一條指派陳述式,但實際上B的建構函式幹了兩件事:先暗地裡建立m_a對象(調用了A的無參數建構函式),再調用類A的賦值函數,將參數a賦給m_a。
B::B(const A &a)
: m_a(a)
{
…
}
B::B(const A &a)
{
m_a = a;
…
}
樣本9-2(a) 成員對象在初始化表中被初始化 樣本9-2(b) 成員對象在函數體內被初始化
對於內部資料類型的資料成員而言,兩種初始化方式的效率幾乎沒有區別,但後者的程式版式似乎更清晰些。若類F的聲明如下:
class F
{
public:
F(int x, int y); // 建構函式
private:
int m_x, m_y;
int m_i, m_j;
}
樣本9-2(c)中F的建構函式採用了第一種初始化方式,樣本9-2(d)中F的建構函式採用了第二種初始化方式。
F::F(int x, int y)
: m_x(x), m_y(y)
{
m_i = 0;
m_j = 0;
}
F::F(int x, int y)
{
m_x = x;
m_y = y;
m_i = 0;
m_j = 0;
}
樣本9-2(c) 資料成員在初始化表中被初始化 樣本9-2(d) 資料成員在函數體內被初始化