class GamePlayer{ private: static const int NumTurns=5;//常量声明式 int scores[NumTurns];//使用该常量 ... };
文中明确指出,NumTurns为声明式而非定义式。这与我们平时理解一个变量初始化赋值后即肯定被定义,这一观念相违背。而通过实验我们发现NumTurns确实未被定义,NumTurns仅仅完成声明,并在类编译过程中被5所替代。那么为什么会出现这么奇怪的现象呢?
1、首先需要从const谈起。我们知道由const修饰的变量其对应的数值保持恒定不变。类的成员变量,如果由const 修饰,能且只能在构造函数的初始化列表中完成初始化。例:
class A { public: A():a(1){} private: const a; };
原因在于const成员变量,它属于类生成的对象,在每一个对象中都包含了一个相应的const成员变量。在建立对象的过程中完成const成员变量的初始化。而必须在初始化列表中完成初始化则是由于当const成员变量出现在构造函数体内时默认完成的是赋值操作。这与const成员变量必须保持相应的值不变相矛盾。
2、与const成员变量相对应的是static成员变量。当static修饰成员变量的时候,表示相应的成员变量直接属于类本身,为类生成的所有对象共有。我们在统计对象的数量时,可以通过使用static成员变量来实现。同时static相当于一个范围限定符,它限定所修饰的成员变量为该文件所特有。类的static成员变量,在类体外完成初始化,例:
class B { public: B(){} private: static int a; }; int B::a=2;//在类外初始化时,省略掉static,避免与其他全局static变量混淆
3、既然已经有了const、static成员变量,那么static const 成员变量的产生也就顺理成章了。static const成员变量可以认为是该文件一个专属的成员变量,它属于类本身,并为所有对象、友元函数所共享。
static const成员变量初始化方式,与static成员变量相同,例:
class C { public: C(){} private: static const string s; }; const string C::s="hello world";//在类体外初始化,同样省略掉static
4、static const int NumTurns=5
新的C++编译器对此的解释为:当一个变量为class专属的const常量,同时为整型(包括int、char、bool等),可以在声明时完成初始化操作。static const 整型变量的定义同普通的static const 成员变量,还需要在类体外完成初始化。回来最初的例子中:
class GamePlayer{ private: static const int NumTurns=5;//常量声明式 int scores[NumTurns]; ... }; const int GamePlayer::NumTurns;//完成NumTurns的定义,无此句依然可以通过编译
在过去的C++编译器中,是不允许在声明时初始化,现在几乎所有的编译器都支持这一行为。其背后的原因主要如下:
2)为了更好的替代C中的宏。C语言中的宏在预编译阶段即完成替换,static const 整型成员变量可以类似于宏那样工作,同时限定了作用域。从这方面来说,是一个更好的宏的替代方案。
3)契合C++的设计理念。对于同一种功能要求,C++总能提供不同的解决方法以供使用。static const int 与enum遥相呼应,enum也是使用一个记号标明对应的值。使用enum的情况如下:
class GamePlayer{ private: enum {NumTurns=5};//"the enum hack"——令NumTurns 成为5的一个记号名称 int scores[NumTurns]; ... };