书中原话:“**请通过成员初始化器显式地初始化成员对象,这样,可以避免‘双重初始化’成员对象的开销,一次是当成员对象的默认构造函数被调用时,另一次就是在构造函数体中(或者后来)调用设置函数被初始化成员对象时**。”
类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成
比如说
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
A(A& a) { cout << "A::A" << endl; }
};
class B
{
private:
A a;
public:
B():a() { }
};
int main() {
B b;
return 0;
}
A::A
而
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
A(A& a) { cout << "A::A" << endl; }
};
class B
{
private:
A a;
public:
B() { a = A(); }
};
int main() {
B b;
return 0;
}
A::A
A::A
后一个版本就是双重初始化。
看一下这段代码,使用两种类初始化方式来初始化成员类变量,第一次使用不含参构造,不调用成员变量初始化;第二次使用含参构造,对应调用成员变量初始化。
输出的结果是下图,不调用成员初始化的构造函数时,成员函数调用了两次设置变量的函数,而这两句在程序中都是初始化的作用,即双重初始化。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
class component{
private:
int a, b;
void _set(int _a, int _b){
cout << "Set a = " << _a << ", b = " << _b << endl;
a = _a; b = _b;
}
public:
component(){ _set(0, 0); }
component(int a, int b){ _set(a, b); }
void setValue(int a, int b){ _set(a, b); }
};
class test{
private:
component com;
public:
test(){ com.setValue(5,4); }
test(int a, int b):com(a, b){ }
};
int main(){
cout << "双重初始化" << endl;
test t1;
cout << "单次初始化" << endl;
test t2(5, 4);
return 0;
}
运行结果是这样的