有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同。这些特殊的类型的成员变量包括:
a.引用
b.常量
c.静态
d.静态常量(整型)
e.静态常量(非整型)
常量和引用,必须通过参数列表进行初始化。
静态成员变量的初始化也有点特别,是在类外初始化且不能再带有static关键字。
#include <iostream> using namespace std; class BClass{ public: BClass():i(1),ci(2),ri(i){} //对于常量型成员变量或者引用型成员变量,必须要用构造函数初始 //化列表初始化;对于普通成员变量,其本质已经是赋值了,效率也低 private: int i; //普通变量 const int ci; //常量成员变量 int &ri; //引用变量 static int si; //静态成员变量 //static int si2=100; //error!!只有静态常量成员变量,才可以初始化 static int si2; static const int sci; //静态常量成员变量 static const int sci2=100; //静态常量成员的初始化 static const double scd; //静态常量成员变量 //static const double scd2=100.0; //error!!只有静态常量整型数据才可以在类中初始化 }; /*注意下面3行,不能再带有 static */ int BClass::si2=100; const int BClass::sci=100; const double BClass::scd=100.0; const int BClass::sci2; //根据著名大师Stanley B.Lippman的说法这行是必须的, //但这其实和具体的编译器有关。 int main() { BClass B; return 0; }
静态成员属于类作用域,但不属于类对象,和普通的static变量一样,程序一运行就分配内存并初始化,生命周期和程序一致。可以这么理解:在类中,只是声明了静态变量,并没有定义。而恰恰是因为仅仅做了声明,所以并不为其分配内存,只有当定义了以后才分配内存。(注意:如果在类里面这么写: int a; 那么是既声明了变量,也定义了变量,两者合在一起了。)
静态成员其实和全局变量地位是一样的,是“类级别”的,也就是它和类的地位相同,只不过编译器把它的使用限制在类作用域内(不是类对象,它不属于类对象成员),要在类的定义外(不是类作用域外)初始化。而普通成员是“对象级别”的。类级别的成员,先于该类任何对象的存在而存在,它被该类所有的对象共享。
所以,在类的构造函数里初始化static变量显然是不合理的。假定要实例化该类的一个对象,那么会发生什么事情呢?静态成员肯定要出现在这个对象里面的。这时候才去定义那个静态成员吗?这显然是不合适的。因为,比如有另外一个线程也要创建该类的对象,那么也要按照这个方式去定义那个静态成员。这会产生两种可能的情况:1. 重复定义;2. 就算不产生重复定义的情况,也会产生竞争,从而造成死锁的问题,以至于对象无法创建。很显然,编译器不能这么干。那么很合理的解决办法,就是事先在类的外部把它定义好,然后再供所有的对象共享。