在构造函数中使用初始化列表(Initializer List),能够使执行效率更高,能使得成员变量在创建时即初始化,同时要求初始化列表的顺序与成员变量的声明顺序一致。
现代 c++的类成员,可以在声明成员变量时直接写好默认值,这种方法叫法brace-or-equal-initializers,即使用花括号和等号均可,同时任何静态的函数或者变量都可以作为初始值,尽管这会带来一些消耗,但能够很好的防止奇葩问题的发生。
static int _default_age() {
return 88;
}
class Student
{
string name_ = "anonymous";
int age_ = _default_age();
};
在以往,我们创建一个结构体时,需要memset一把,来把该块内存初始化为0,而如果里面有涉及string或者vector之类的成员变量,又有我们想初始化为0的int/float,就只能一个一个赋值了,这让代码变得冗长。而现代c++提供了默认的办法,可以更合理地『清零』,即普通类型置0,有默认构造函数的调用构造函数。使用空的花括号即搞定:
struct Info
{
string favo_food;
float weight;
int height;
};
Info info = {};
未初始化的变量,在debug模式下可能会由编译器帮忙置0,但是在开启优化的release模式下,就会变成各种乱七八糟的值了。
这时就出现一个优先次序问题了:如果构造函数里既使用了初始化列表,变量声明也设置了默认值,而结构体类型的变量也设置了默认清零,结果会是如何呢?
static int _default_age() {
return 88;
}
struct Info
{
string favo_food;
float weight;
int height = 99;
};
class Student
{
public:
Student() {};
Student(const char *name, int age) : name_(name), age_(age) {
}
void print_info() {
cout << name_ << " " << age_ << endl;
cout << info_.favo_food << " " << info_.weight << " " << info_.height << endl;
}
private:
string name_ = "anonymous";
int age_ = _default_age();
Info info_ = {};
};
int main()
{
Student s;
s.print_info();
Student s2("zhang san", 100);
s2.print_info();
return 0;
}
结果非常合理且易于理解:构造函数的初始化列表会覆盖声明时的默认值,info_ = {}只会对没有默认值的字段做清零操作。