A: 如何在类中定义常量?
Q: 如果你想得到一个可用于常量表达式中的常量,例如数组大小的定义,那么你有两种选择:
class X {
static const int c1 = 7;
enum { c2 = 19 };
char v1[c1];
char v2[c2];
// ...
};
一眼望去,c1的定义似乎更加直截了当,但别忘了只有static的整型或枚举型量才能如此初始化。这就很有局限性,例如:
class Y {
const int c3 = 7;// error: not static
static int c4 = 7;// error: not const
static const float c5 = 7;// error not integral
};
我还是更喜欢玩“enum戏法”,因为这种定义可移植性好,而且不会引诱我去使用非标准的“类内初始化”扩展语法。
那么,为何要有这些不方便的限制?因为类通常声明在头文件中,而头文件往往被许多单元所包含。[所以,类可能会被重复声明。]但是,为了避免链接器设计的复杂化,C++要求每个对象都只能被定义一次。如果C++允许类内定义要作为对象被存在内存中的实体,那么这项要求就无法满足了。关于C++设计时的一些折衷,参见《The Design and Evolution of C++》。
如果这个常量不需要被用于常量表达式,那么你的选择余地就比较大了:
class Z {
static char* p;// initialize in definition
const int i;// initialize in constructor
public:
Z(int ii) :i(ii) { }
};
char* Z::p = "hello, there ";
只有当static成员是在类外被定义的,你才可以获取它的地址,例如:
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7;// definition
int f()
{
const int* p1 = &AE::c6;// error: c6 not an lvalue
const int* p2 = &AE::c7;// ok
// ...
}
const int 和const 浮点型可以在类中定义,既然已经定义过了,编译器就会为它分配内存。那么类外的const int A::i;就不会被视为定义而被编译器认为是一个重复申明,所以就不必要了。
而普通类型,如static char* p在类中的只是申明,编译器不会为它分配内存,所以要在类外执行一个定义,为p分配内存。
如:
class A{
static char *p; //申明
}
char* A::p; //定义,为p分配内存,否则后面程序有调用p则显示unresolved symbol p
c++标准中仍然是只有integer类型的数据可以在类内初始化(注意是初始化,不是定义),并且还是必须在类外定义。
而上面几位说的都是对的,那些只是编译的扩展,而不是标准了。
在类中定义常量的几个做法
方法一:(错误)
class Test
{
const int size = 100;
int array[size];
//……
};
错误原因:
1:因为在一个类中,const恢复了它在c中的一部分意思,在每个类对象里分配存储并代表一个值,这个值一旦被初始化以后就不能被改变。所以在类中使用了const的意思是:在这个对象的生命周期内,它是一个常量。
然而,每个对象可能包含不同的值。
2:对const常量进行了初始化,C++中这个初始化必须由构造函数完成,如const常量在初始化列表中进行初始化。
方法二:(正确,有缺陷)
使用enum;
class Test
{
enum { size = 100};
int array[size];
//……
};
使用enum不会占用对象中的存储空间的,枚举常量在编译的时候被全部求值。
缺点:
假如定义一个非整型的常量该如何?enum无法完成此项操作,同时丧失了枚举本来的作用。
方法三:(正确,最好)
使用静态常量;
class Test
{
static const int size;
int array[size];
//……
};
const int Test::size = 100;
它既是常量,不能改变,又是静态,在类中只有一个定义点。所以能够完成任务。
同时,它可以定义任何与定义类型的常量。