1、必须用初始化列表的场景
(1)成员变量是引用类型,必须在初始化列表中初始化。
(2)成员变量是const类型,必须在初始化列表中初始化。
(3)如果类继承自一个父类,并且父类中有带初始化列表的构造函数,必须在初始化列表中初始化父类。
class Base {
public:Base(int i) { }
};class Derive:public Base {
public:Derive(int i) : Base(i){}
};
(4)成员变量是类类型,且这个类的构造函数带参数。
class Item {
public:Item(int i) { }
};class MyDemo {
public:MyDemo(int i) : item(i){}Item item;
};
2、初始化列表的执行时机
初始化列表是在构造函数之前执行的。
我们可以用下面的代码来验证:
class Item {
public:Item() { }Item(const Item& _item) {cout << " Item拷贝构造函数" << endl;}
};
class Derive {
public:Derive() { cout << " Derive默认构造函数" << endl; }Derive(Item& _item) : item(_item) { cout << " Derive带初始化列表构造函数" << endl; }Item item;
};int main()
{Item _item;Derive derive(_item);return 0;
}
执行结果如下:
从运行结果看,初始化列表是在构造函数之前运行的。
3、按成员变量的声明顺序初始化,而不是根据初始化列表中的前后顺序。
class X{
public: X(int val) : j(val), i(j){}
private:int i;int j;
}
其实在这个时候,构造函数是这么初始化的:
X::X(int val){i = j;j = val;
}
所以最终的结果是j = val, 但i的值未知。
4、初始化列表的优点
一般地,放在构造函数初始化列表中进行初始化,比放在构造函数中初始化效率更高。
我们可以通过代码来验证这个结论:
(1)构造函数中初始化
class Item {
public:Item() { cout << " Item默认构造函数" << endl; }Item(int i) { cout << " Item(int)构造函数" << endl; }Item(const Item& _item) {cout << " Item拷贝构造函数" << endl;}Item& operator = (const Item& _item) {cout << " Item拷贝赋值运算符" << endl;return *this;}
};class Derive {
public:Derive(int i){ item = Item(i);cout << " Derive带初始化列表构造函数" << endl; }Item item;
};int main()
{Derive derive(2);return 0;
}
运行结果:
(2)初始化列表中初始化
Derive(int i) : item(i){}
运行结果:
可以看到,初始化列表初始化时少了1次默认构造函数和1次拷贝赋值运算符。