初始化列表 (Initializer List)
我们先定义一个Student类:
class Student {
private:
string name;
public:
Student(string s);
};
Student类具有一个数据成员name,还有一个构造函数。
我们再定义这个构造函数,有如下两种方式:
1.初始化列表(Initializer List)
Student::Student(string s) : name(s) {}
- 赋值(Assignment)
Student::Student(string s) { name = s;}
这两种方式虽然最终的效果一样,但是在实现过程中存在差异,简单地说,第二种方法虽然合法但是草率,数据成员name将在构造函数体之前执行默认初始化,再进行赋值,而第一种方法直接进行初始化。所以,虽然这两种方法的效果是一样的,但是,有些时候必须使用初始化列表:
当成员是const或者是引用时,必须将其初始化,这里借用一下《C++ Primer》中的例子来说明:
class Constref {
public:
Constref(int ii);
private:
int i;
const int ci;
int &ri;
};
构造函数如下:
Constref::Constref(int ii)
{ //赋值
i = ii;
ci = ii;
ri = i;
}
我们在vs上看一下编译是否能通过,但是这段代码写完就发出警示了,如下:

所以,如果成员中如果是cons或者是引用的话,还是使用初始化列表,如下:
Constref::Constref(int ii) :i(ii), ci(ii), ri(i) {}
建议: 使用构造函数初始值
在很多类中,初始化和赋值的区别事关底层效率问题:前者直接初始化数据成员,后者则先初始化再赋值。
除了效率问题外更重要的是,一些数据成员必须被初始化,建议读者养成使用构造函数初始值的习惯,这样能避免某些意想不到的编译错误,特别是遇到有的类含有需要构造函数初始值的成员时。
(From 《C++ Primer》)
还有一个问题需要注意的是成员初始化的顺序,看下面一个例子:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
class A {
private:
int i;
int j;
public:
A(int val): j(val), i(j) { }
void f();
};
void A::f()
{
cout << i << " " << j << endl;
}
int main()
{
A a(10);
a.f();
while (1);
return 0;
}
上面这个例子中,构造函数是先初始化 j 再初始化 i 的,这与声明的顺序不一致,可能凭感觉来说这并没有什么问题,但是,我们运行一下:

很明显,i 的初始化产生问题了,从形势上来看,仿佛是先用val初始化了j,再用 j 初始化 i ,实际上,成员的初始化顺序与它们在类定义中的出现顺序一致,即 i 先被初始化,因此这个初始值的效果是试图用未定义的值 j 来初始化 i ,这当然会出现一些无法预料的结果,所以,最好令构造函数初始值的初始顺序与成员声明的顺序一致,并且尽量避免使用某些成员初始化其他成员。
网友评论