在c++11以前,标准只允许常量的静态成员变量并且只能是整形或枚举型才能“就地(in-class)”初始化。并且static数据成员必须在类定义的外部进行定义。
class A { private: static const int period = 30; double daily_tbl[period]; // ok: period is constant expression }; // definition of static member with no initializer; // the initial value is specified inside the class definition const int A::period;
对于非const的static数据成员,则不能在类的定义体中初始化,而是在类定义体的外部定义时进行初始化。
class B { private: static int count; }; int B::count = 100;
在c++11中,标准对于成员变量的in-class初始化就宽松多了。c++11允许非静态成员变量进行in-class初始化。
class C { private: int i = 1; double d { 1.2 }; };
c++11支持使用等号(=)和花括号({})两种方式进行非静态成员变量的in-class初始化。
c++11同样支持以前的构造函数初始化列表,或者在构造函数的函数体中对变量进行初始化。
class D { public: D() : i(2) { i = 3; } void print() { cout << "i = " << i << endl; } private: int i = 1; }; int main() { D d; d.print(); return 0; }
程序的输出结果是:“i = 3”。如果把构造函数中的赋值语句“i = 3”去掉,则程序的输出结果是是:“i = 2”。如果把初始化列表中的“i(2)”也去掉,则程序的输出结果是:“i = 1”。
所以,可以这么理解。程序先执行in-class初始化,然后是构造函数的初始化列表,最后是构造函数的函数体。
那这种in-class初始化有什么好处呢?在c++11之前,如果一个类有很多成员变量,那我们可能需要编写很多个构造函数,分别对应不同的初始化方式。在以前,可以通过调用公共的初始化函数来达到这个目的,那现在就可以使用in-class初始化的方式了,这种方式书写更简单,且效率也更高。
class E { E() {} //不需要初始化i, d, s E(int a) : i(a) {} //不需要初始化d, s E(double b) : d(b) {} //不需要初始化i, s E(string c) : s(c) {} //不需要初始化i, d, E(int a, double b) : i(a), d(b) {} //不需要初始化s E(int a, string c) : i(a), s(c) {} //不需要初始化d E(double b, string c) : d(b), s(c) {} //不需要初始化i E(int a, double b, string c) : i(a), d(b), s(c) {} private: int i = 100; double d = 1.2; string s = "in-class initialization. "; };
最后,对于非常量的静态成员变量,c++11和c++98保持一致:还需要到头文件以外去定义它。
学习资料: 《深入理解c++11》