C++成员初始化列表
首先明确,成员初始化列表只能用于构造函数
1.使用成员初始化列表的情况
I>初始化非静态const成员变量
class A{
private:
const int a;
public:
A();
};
怎么编写构造函数来初始化成员变量a呢?
可能会想到这样
A::A(){
a = value;
}
其实这是一个赋值过程,在执赋值之前,初始化已经完成了,const变量是不可以被赋值的,只能在初始化的时候给一个值
所以这里用到成员初始化列表,成员初始化列表指出了怎样初始化
A::A() : a(value){}
II>初始化成员引用
class A{
private:
int &a;
public:
A();
}
与非静态const成员一样,左引用绑定一个左值只能在初始化阶段完成,所以这里用到成员初始化列表,成员初始化列表指出了怎样初始化
A::A() : a(left_value){}
III>初始化基类成员
基类:
class ClassBase{
private:
int a;
public:
ClassBase();
ClassBase(int a);
}
派生类:
class ClassDerived:public ClassBase{
private:
...派生类扩展的成员
public:
ClassDerived(int x);
}
public继承会继承基类的私有成员,但是只能由基类的接口访问,所以对于派生类的构造函数,不能简单的使用赋值进行初始化基类成员
因此,在执行派生类构造函数之前,要先执行基类的构造函数
同样,可以使用成员初始化列表,表示基类怎样初始化 ,也就是说,显式的告诉编译器调用哪一个构造函数初始化基类成员
调用基类的有参构造
ClassDerived::ClassDerived(int x):ClassBase(x){
...
}
调用基类的无参构造
ClassDerived::ClassDerived() : ClassBase(){
...
}
ClassDerived::ClassDerived(){
...
}
成员初始化列表不表示构造函数调用过程,表示了调用哪一个,如果不加成员初始化列表,则表示基类调用默认构造函数(无参的构造函数)
IV>初始化其他类的对象成员
class A {
public:
A();
A(int a);
const A &operator=(const A &obj);
};
A::A() {
cout << "A()" << endl;
}
A::A(int a) {
cout << "A(int)" << endl;
}
const A &A::operator=(const A &obj) {
cout << "A::operator=(const A &)" << endl;
return obj;
}
class B {
private:
A objA1;
A objA2;
public:
B();
};
可以怎样初始化B的对象中的objA1和objA2呢?
第一种,赋值
B::B() {
objA1 = A();
objA2 = A(3);
}
int main() {
B objb;
return 0;
}
输出:
A()
A()
A() << 生成临时对象调用无参构造
A::operator=(const A &) << objA1.operator=(上面的临时对象)
A(int) << 生成临时对象调用有参构造
A::operator=(const A &) << objA2.operator=(上面的临时对象)
通过分分析,可以发现,在执行函数体之前,已经调用过两次默认的构造函数,可以使用成员初始化列表,在初始化阶段(构造函数体执行之前)表示调用哪一个构造函数
B::B() : objA1(), objA2(3){}
输出:
A()
A(int)
如果调用默认的无参构造,可以省略
比较发现,使用成员初始化列表的效率会比赋值高得多
2.总结一下
I>成员初始化列表作用在初始化阶段
对于基本类型来说,初始化和赋值没什么区别。
对于类对象:初始化列表表示了调用哪一个构造函数,不写初始化列表表示调用默认。