8.4.2 编译期间类里的常量

上面所使用的const是有趣的,也可能很有用,但是它没有解决最初的问题,这就是:如何让一个类有编译期间的常量成员?这就要求使用另外一个关键字static,在第10章才会对它进行详尽的介绍。在这种情形下,关键字static意味着“不管类的对象被创建多少次,都只有一个实例”,这正是所需要的:类中的一个常量成员,在该类的所有对象中它都一样。因此,一个内建类型的static const可以看做一个编译期间的常量。

必须在static const定义的地方对它进行初始化。这是在类中使用static const的特征之一,也显得有点与众不同。这种情况只会伴随static const一起出现:也许更喜欢把它用在其他情况下,但不行,因为所有其他的数据成员也必须在构造函数或其他成员函数里初始化。

下面有一个例子,它说明了在一个类里创建和使用一个叫做size的static const,这个类表示一个存放字符串指针的栈[1]

8.4.2 编译期间类里的常量 - 图1

8.4.2 编译期间类里的常量 - 图2

因为size用来决定数组stack的大小,所以,它实际上是一个编译期间常量,但隐藏在类中。

注意push()带有一个const string参数,pop()返回一个const string,StringStack保存const string*。否则,就不能用StringStack存放在iceCream中的指针。可是,它阻止程序员做改变包含在StringStack中的对象的任何事情。当然,这种限制不是普遍存在的。

8.4.2.1 旧代码中的“enum hack”

在旧版本的C++中,不支持在类中使用static const。这意味着const对在类中的常量表达式不起作用,不过,人们还是想做到这一点。于是,一个典型的解决办法就是使用不带实例的无标记enum(通常称为“enum hack”)。一个枚举在编译期间必须有值,它在类中局部出现,而且它的值对于常量表达式是可以使用的。所以有下面的代码:

8.4.2 编译期间类里的常量 - 图3

这里使用的enum保证不占用对象的存储空间,编译期间得到枚举值。也可以明确地给枚举元素赋值。如下所示:

8.4.2 编译期间类里的常量 - 图4

在一个完整的enum类型中,要是没有为枚举元素特别指定值的话,编译器会从最近的值开始计算,例如上面的three的值为3。

在上面StringStack.cpp中,可以把

8.4.2 编译期间类里的常量 - 图5

替换为

8.4.2 编译期间类里的常量 - 图6

虽然会经常在以前的程序代码里看到使用enum技术,但在C++中增加了static const特性,正是为了解决这个问题。但是,没有绝对的理由说明一定要优先选择static const而尽量不用enum hack,本书使用enum hack是由于写这本书的时候大多数的编译器都支持这种特性。

[1]在写本书时,并不是所有的编译器都支持该特征。