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) 數據成員在函數體內被初始化