我们知道在C++里,对象的构造是由构造函数完成的,一般的我们会在构造函数体内完成成员的初始化工作,像下面这样:
class X
{
public:
X(int val) {i =val;j=i;}
public:
int i;
int j;
}
这是比较简单的一种情况,因为它没有涉及到有虚函数以及继承链里有虚基类的情况,在有虚函数的情况一下,一般是编译器会在构造函数中(由编译器合成或者是开发着提供)安插vptr指针,并妥当的设置好它的值,使得它指向该类的虚函数表,虚函数表也是在编译期间完成的,这里不再细说。
构造函数的另外一种语法就是本文的主题:成员初始化列表。像下面这样:
class X
{
public:
X(int val):i(val),j(i){}
public:
int i;
int j;
}
成员初始化列表并不是一种函数调用,初始化成员的次序非常讲究,编译器真正初始化成员的顺序是按照它们在类中申明的次序的,而并不是列在成员初始化列表里的顺序,上面的示例中的初始化没有任何问题,咱们再来看一种情况,你会得到一个怪异的结果。
class X
{
public:
X(int val):j(val),i(j){}
public:
int i;
int j;
}
看出区别了吗?成员初始化列表里面的次序发生了变化,我们来简单的测试一下到底有什么不同。
#include <iostream>
using std::cout;
using std::endl;
class X
{
public:
X(int val):i(val),j(i){}
public:
int i;
int j;
};
int main()
{
X x(100);
cout << x.i << endl << x.j << endl;
return 0;
}
输出:
100
100
没有任何问题,再来看上面的后一种情况。
#include <iostream>
using std::cout;
using std::endl;
class X
{
public:
X(int val):j(val),i(j){}
public:
int i;
int j;
};
int main()
{
X x(100);
cout << x.i << endl << x.j << endl;
return 0;
}
输出:
10653684
100
显然不是我们要的结果,对不对?这是因为,编译器是按照申明次序来进行初始化的,所以先初始化i,这时候j是未初始化过的,因此得到的时候脏数据。gcc/g++编译器能对这种情况给出警告,像下面这样
g++ -c -Wall -O3 hello.cpp -o hello.o
hello.cpp: In constructor `X::X(int)':
hello.cpp:12: warning: `X::j' will be initialized after
hello.cpp:11: warning: `int X::i'
hello.cpp:9: warning: when initialized here
g++ -o hello hello.o
如果没有对成员初始化列表这样的理解,估计大家对这样的警告有所不理解,另外,下面这四种情况下是必须要用成员初始化列表语法来初始化成员的:
1.初始化一个reference member
2.初始化一个const member
3.调用一个base class的构造函数,而它拥有一组参数
4.调用一个member class的构造函数,而它拥有一组参数
最后一点,当成员都是基本类型时,两种构造方法在效率上没有任何区别,当成员有class对象时,情况就不一样,在构造函数体中通过赋值运算符=进行初始化时,会产生临时对象,在用成员初始化列表进行构造时,会直接调用class 成员的copy 构造函数,效率上会有所提升,不过现在的编译器将做何种优化也视不同的编译器而异。举个例子:
class Word
{
public;
Word(){name=0;cnt=0;}
public:
string name;
int cnt;
}
编译器对构造函数可能做的扩张如下:
Word::Word()
{
name.string::String();
string temp = string(0);
name.string::operator=(temp);
temp.string::~string();
cnt=0
}
继续
class Word
{
public:
Word():name(0)
{cnt=0;}
public:
string name;
int cnt;
}
编译器对构造函数可能做的扩张如下:
Word::Word()
{
name.string::string(0);
cnt = 0;
}
完。