C++在類的構造函數中,能夠兩種方式初始化成員數據(data member)。html
1,在構造函數的實現中,初始類的成員數據。諸如:
class point
{
private:
int x,y;
public:
point(int m=0,int n=0)
{
x=m;
y=n;
}
int GetX()
{
return x;
}
int GetY()
{
return y;
}
};
2,還能夠定義初始化成員列表(Initializer list)來初始化成員數據(data member)。
改寫構造函數以下:
point(int m=0,int n=0):x(m),y(n)
{
}
這樣咋一看沒有什麼不一樣,確實,對於上面的這種簡單列子來講,也真的沒有太大不一樣。
那咱們爲何要用初始化成員列表,何時用初始化成員列表來初始化成員數據呢?Lippman的《C++ Primer》中提到在如下三種狀況下須要使用初始化成員列表:
一,須要初始化的數據成員是對象的狀況;
二,須要初始化const修飾的類成員;
三,須要初始化引用成員數據;
如今分別舉例說明:
一,須要初始化的數據成員是對象。
---------------------------
#include <stdio.h>
class point
{
protected:
int m_x,m_y;
public:
point(int m=0,int n=0)
{
m_x = m;
m_y = n;
printf("constructor called!/n");
}
point(point& p)
{
m_x = p.GetX();
m_y = p.GetY();
printf("copy constructor called!/n");
}
int GetX()
{
return m_x;
}
int GetY()
{
return m_y;
}
};
class point3d
{
private:
point m_p;
int m_z;
public:
point3d(point p, int k)
{
m_p = p; //這裏是對m_p的賦值
m_z=k;
}
point3d(int i,int j, int k):m_p(i,j) // 至關於 point m_p(i,j)這樣對m_p初始化
{
m_z=k;
}
void Print()
{
printf("%d,%d,%d /n",m_p.GetX(),m_p.GetY(),m_z);
}
};
---------------------------------------
上述代碼中Point3d是一個3D座標,他有一個point的2D座標和一個成員組成。
咱們如今想定義一個3D座標p3d,能夠這樣實現:
void main()
{
point p(1,2); //先定義一個2D座標
point3d p3d(p,3);
p3d.Print();
}
從point3d實現體能夠看出,咱們是經過對m_p進行賦值,這樣不只調用copy constructor產生
臨時對象並且是對m_p的一個賦值操做。
而若是使用成員初始化列表,咱們則能夠這樣:
void main()
{
point p(1,2);
point3d p3d(1,2,3);
p3d.Print();
}
p3d中的point型成員是經過調用初始化的方式構建的。因爲對象賦值比初始化要麻煩的多,所以也帶來的性能上的消耗。(能夠參見Scott Meyers著《effective C++》條款12)。
這也是咱們在對成員數據是對象成員的採用初始化列表進行初始始化的主要緣由。
二,須要初始化const修飾的類成員;
三,須要初始化引用成員數據;
對於類成員是const修飾,或是引用類型的狀況,是不容許賦值操做的,(顯然嘛,const就是防止被錯誤賦值的,引用類型必須定義賦值在一塊兒)所以只能用初始化列表對齊進行初始化。
上面兩點比較好明白,能夠用一個例子加以說明:
-------------------------------------
#include <stdio.h>
class base
{
private:
const int a;
int& b;
public:
// base(int m, int n)
// {
// a = m;
// b = n;
// }
base(int m, int n):a(m),b(n)
{}
};
void main()
{
base ba(1,2);
}
---------------------------
上面紅色的部分初始化的方式是不容許的通不過編譯,經過初始化列表則能夠很好的定義。