C++的构造函数初始化列表使用规则如下:
- 如果存在基类,派生类可以直接在初始化列表中调用基类的构造函数并传递参数。
- 非静态const成员或者引用必须在初始化列表中进行初始化,因为他们只存在初始化语义而不存在赋值语义。
- 类的数据成员的初始化可以采用初始化列表或函数体内赋值两种方式,这两种方式的效率不同。
class A {
public
:
A() {
cout<<
"A()"
<<
endl
;
}
A(
const
A
& other) {
cout<<
"copy"
<<
endl
;
}
A
& operator = (
const
A
& other) {
cout<<
"operator = "
<<
endl
;
return
(*
this
);
}
};
class
B
{
public
:
B(
const
A
&);
B(
const
A
& a,
int
i);
private
:
A
m_a
;
const
int
x
;
};
//B::B( const A& a):m_a(a),x(5){} //(1)
B::B(
const
A
& a):
x
(5) {
m_a
= a;
}
int
main() {
A
a;
B
b(a);
return
0;
}
输出结果:
A()
A()
operator =
在函数体重赋值的初始化方式,是先创建一个临时的对象,然后再通过赋值函数给对象赋值的,明显效率要比直接在初始化列表中初始化要低。
如果采用(1)的方式则只调用了A 拷贝构造函数。输出是
A()
copy
如果把上面的构造函数改成
B::B( const A & a) {
m_a
= a;
}
编译器会报错,因为没有初始化话常量x,在构造函数中加多一句x = 5;也不行,编译器会提示x 是read only的不能被赋值。所以非静态的const数据成员只能在构造函数的初始化列表中初始化,引用也是一样的道理。静态的数据成员则可以在声明它的时候就初始化例如
static const int x =5;
当使用成员初始化列表来初始化数据成员的时候,这些成员真正的初始化顺序并不一定与你在初始化列表中为它们安排的顺序一致,编译器总是按照它们在类中声明的次序来初始化的。因此,最好是按照它们的声明顺序来书写初始化列表:
(1)调用基类的构造函数,向它们传递参数;
(2)初始化本类的数据成员;
(3)在函数体内完成其他的初始化工作;
参考文献
《高质量程序设计指南-C/C++》