C++学习 细谈成员初始化列表
直接上代码
上面红色框起来的部分就是类成员初始化列表,成员初始化列表一般用在类的构造函数中,包括拷贝构造函数。对于这种用法,作为C++程序员一点都不陌生。下面从几个疑惑开始讲解,成员初始化列表:
1.什么时候必须要使用初始化列表
(1)初始化成员有引用
以上代码编译器会报错,编译器不允许这样初始化,至于为什么不允许,后面再探讨,只能按照一下方式来初始化引用成员数据
这样编译器就不会报错了
(2)初始化const类型成员
这样初始化const 类型成员编译器会报错,至于编译器为什么会允许这样做,还没明白。按照以下做法就不会报错
(3)类继承于一个父类,且父类含有有参数的构造函数
(3)含有类成员变量,且类成员的构造函数有参数
2.为什么要使用成员初始化列表,答案是为了提高程序的效率
既然发明了这个语法,一定有一定的道理,且一定有利于程序的运行。以下代码可以非常清晰的说明:
class A {
public:
int m_a;
int m_b;
A(){
cout << "A 的构造函数" << endl;
}
A(int tmp):m_a(tmp),m_b(tmp) {
cout << "A 的拷贝构造函数" << endl;
}
~A() {
cout << "A 的析构函数" << endl;
}
};
class B {
public:
int tt_a;
int tt_b;
A m_aobj;
B(int a, int b) : tt_a(a), tt_b(b) {
m_aobj = a;
cout << "B 的构造函数" << endl;
}
~B() {
cout << "B 的析构函数" << endl;
}
};
int main()
{
//A a_obj1(10,20);
B b(10, 20);
std::cout << "Hello World!\n";
return 0;
}
这时候m_aobj 成员我们没有用初始化列表来初始化,运行结果为
如果m_aobj换成在初始化列表中初始化,如下代码
class B {
public:
int tt_a;
int tt_b;
A m_aobj;
B(int a, int b) :m_aobj(a), tt_a(a), tt_b(b) {
//m_aobj = a;
cout << "B 的构造函数" << endl;
}
~B() {
cout << "B 的析构函数" << endl;
}
};
运行结果就变成
很明显的看到后者少调用了一次A的构造函数和一次析构函数。因为前者编译器会生成一个临时对象。由此说明成员初始化列表优化程序运行效率。
(3)使用成员初始化列表需要注意哪些细节
(1)成员初始化列表会被编译器转换为代码并被放在用户代码之前。‘
(2)成员的初始化并不是按照初始化列表的顺序来的,而是按照成员在类的定义顺序来初始化
class A {
public:
int m_a;
int m_b;
A(int a):m_a(a){
cout << "A 的构造函数" << endl;
}
~A() {
cout << "A 的析构函数" << endl;
}
};
class B {
public:
int tt_a;
int tt_b;
B(int a, int b) : tt_a(a), tt_b(b) {
//m_aobj = a;
cout << "B 的构造函数" << endl;
}
~B() {
cout << "B 的析构函数" << endl;
}
};
class C {
public:
A aa;
B bb;
C(int a) :bb(a,a), aa(a) {
cout << "C 的构造函数" << endl;
}
};
int main()
{
//A a_obj1(10,20);
C c(10);
std::cout << "Hello World!\n";
return 0;
}
这里我们的初始化列表顺序是 B A,定义顺序是A B。运行结果如下
显然是按照定义的顺序来初始化的,而不是初始化列表顺序。