为什么人们在C++中使用枚举作为常量,而不是使用const
?
为什么人们在C++中使用枚举作为常量,而不是使用const
?
Bruce Eckel在C++ 编程思想中给出了一个理由:
在旧版本的 C++ 中,类内不支持
static const
。这意味着在类内部,const
对于常量表达式是无效的。然而,人们仍然希望这样做,所以通常的解决方案(通常称为“枚举黑科技”)是使用没有实例的未命名enum
。枚举必须在编译时建立所有其值,它是局部于类的,并且其值可用于常量表达式。因此,您通常会看到:
#include <iostream>
using namespace std;
class Bunch {
enum { size = 1000 };
int i[size];
};
int main() {
cout << "sizeof(Bunch) = " << sizeof(Bunch)
<< ", sizeof(i[1000]) = "
<< sizeof(int[1000]) << endl;
}
enum Color { Red,Green,Blue };
enum Size { Big,Little };
void f( Color c ) {
}
void f( Size s ) {
}
int main() {
f( Red );
f( Big );
}
enum {Margin = 50};
- Claudio枚举是一组相关的常量,因此关于它们之间的关系的附加信息必须对他们手头的问题模型有用。
enum { SOMETHING = 2232; }
(类似这样;未命名的仅有一个值的枚举),而不是const int SOMETHING = 2232;
。这是因为枚举永远不会得到任何存储空间,而常量变量仍然是变量,如果编译器无法证明它不需要一个变量,它将获得(静态)存储空间,而这种情况经常发生。 - Jan Hudec在处理模板元编程时,还有一个历史原因。一些编译器可以使用枚举中的值来实例化类,但不能使用静态常量整数。
template <int N>
struct foo
{
enum { Value = foo<N-1>::Value + N };
};
template <>
struct foo<0>
{
enum { Value = 0; }
};
现在你可以更明智的方式来做:
template <int N>
struct foo
{
static const int Value = foo<N-1>::Value + N;
};
template <>
struct foo<0>
{
static const int Value = 0;
};
另一个可能的原因是,静态常量整数可能在运行时为其保留内存,而枚举类型永远不会有实际的内存位置保留,将在编译时处理。请参见此相关问题。
我喜欢使用枚举类型时能够自动执行的行为,例如:
enum {NONE, START, HEY, HO, LAST};
然后,只需循环直到LAST,当添加新状态(或其他所代表的内容)时,逻辑会自适应。
for (int i = NONE; i < LAST; i++)
{
// Do stuff...
}
添加一些内容...
enum {NONE, START, HEY, WEE, HO, LAST};
循环会根据所处理的输入数据进行适应...
当使用时,枚举更具描述性。考虑以下例子:
int f(int fg, int bg)
相对于
int f(COLOR fg, COLOR bg)
此外,枚举类型提供了更多的类型安全性,因为:
enum class
类型,是一个正统的 C++ 风格的 "重新构想" 枚举类型:隐式转换被禁止,此外值必须始终带有限定名称(qualified name)。这类似于 C# 的枚举类型,并且避免了 C 语言旧版枚举类型中出现的名称冲突和命名空间污染问题。 - motiz88在编译器供应商实现ISO/IEC 14882:1998 C++标准之前,这段代码在类作用域中定义常量会导致编译错误:
class Foo {
static const int MAX_LEN = 80;
...
};
如果常量是整数类型,一种巧妙的解决方法是在类内部定义一个枚举:
class Foo {
enum {
MAX_LEN = 80
};
...
};
枚举类型也可以用作类型名称。因此,您可以定义一个以枚举为参数的函数,这使得清楚了解应该将哪些值作为函数参数给出,与将值定义为const变量并且函数接受"int"作为参数相比更加明确。
考虑以下示例:
enum my_new_fangled_type {
baz = 0,
meh = 1
};
void foo (my_new_fangled_type bar) // bar can be a value listed in the enum
{
...
}
对比:
int const baz = 0;
int const meh = 1;
void foo (int bar) // what are valid values for bar?
{
...
}
my_new_fangled_type
为整型 int
,并声明了一个函数 foo
,该函数参数为 my_new_fangled_type bar
。问题解决了,不需要枚举类型,只需将 typedef int
替换为 typedef uchar
或其他类型即可更改内存表示方式。 :) - weberc2这在一定程度上是因为旧编译器不支持声明真正的类常量。
class C
{
const int ARealConstant = 10;
};
所以必须这样做
。class C
{
enum { ARealConstant = 10 };
};
因此,许多便携式库仍然使用这种形式。
另一个原因是枚举可以作为一种方便的语法设备,将类常量组织成相关和不相关的常量。
class DirectorySearcher
{
enum options
{
showFiles = 0x01,
showDirectories = 0x02,
showLinks = 0x04,
};
};
vs
class Integer
{
enum { treatAsNumeric = true };
enum { treatAsIntegral = true };
enum { treatAsString = false };
};
在调试过程中,一些调试器会显示枚举名称而不是其值,这非常有帮助。我知道我宁愿看到 day_of_week = MONDAY
而不是 day_of_week = 1
。