原文标题:enum vs const
原文作者:Rob Manderson
原文出处:http://www.codeproject.com/cpp/enumvsconst.asp
译文作者:xlander
最近我负责对别人写的一些C++代码进行复查,代码检查能够引起错误的条件,如果一旦发生错误的话,就进行一些合情合理的善后措施。写的很好,不过,就又那么一个小地方让我郁闷的不得了。
由于某些原因,我这里不方便把真实的类展示出来,为类方便问题的说明,我们来人为地杜撰一个。
我所复查的类大概如下:
class CAClass
{
public:
const UINT aConstantOfInterestToThisClass1 = 0;
const UINT aConstantOfInterestToThisClass2 = 1;
CAClass(UINT constValue, LPCTSTR someOtherParameter);
void DoSomething();
private:
UINT m_const;
CString m_parameter;
};
类CAClass的构造函数传入一个它感兴趣的常量参数和一个字符串指针。DoSomething()根据构造函数传入的参数做一些处理。该类的实现代码如下:
CAClass::CAClass(UINT constValue, LPCTSTR someOtherParameter)
{
m_const = constValue;
m_parameter = someOtherParameter;
}
void CAClass::DoSomething()
{
switch (m_const)
{
case aConstantOfInterestToThisClass1:
// Do something defined by this constant.
break;
case aConstantOfInterestToThisClass2:
// Do something defined by this constant.
break;
default:
// It's not a valid value, raise an exception
RaiseException(ERROR);
break;
}
}
这段代码能够正常工作,那么问题出在哪儿呢?
如果是我的话,我会怎么做?
class CBClass
{
public:
enum constsOfInterestToThisClass
{
bConstantOfInterestToThisClass1 = 0,
bConstantOfInterestToThisClass2 = 1,
};
CBClass(constsOfInterestToThisClass constValue,
LPCTSTR someOtherParameter);
void DoSomething();
private:
constsOfInterestToThisClass m_const;
CString m_parameter;
};
实现代码:
CBClass::CBClass(constsOfInterestToThisClass constValue,
LPCTSTR someOtherParameter)
{
m_const = constValue;
m_parameter = someOtherParameter;
}
void CBClass::DoSomething()
{
switch (m_const)
{
case bConstantOfInterestToThisClass1:
// Do something defined by this constant.
break;
case bConstantOfInterestToThisClass2:
// Do something defined by this constant.
break;
default:
// It's not a valid value, raise an exception
RaiseException(ERROR);
break;
}
}
这几乎没有任何差别,任何C++编译器都能够为这两个类产生相同的代码。
那么差别在哪儿呢?
第一个类,CAClass,为自己定义了一组常量。第二个类也定义了同样含义的一组常量,但它的形式是enum。Enum可以用来定义一个包含所有合法取值的有限集合,也可被用作伪数据类型(pseudo datatype),看一眼两个构造函数的区别:
CAClass(UINT constValue, LPCTSTR someOtherParameter);
CBClass(constsOfInterestToThisClass constValue, LPCTSTR someOtherParameter);
CAClass能够接受任何合法的UINT值,在将近40亿个可能取值中,只有两个是该类所感兴趣的。任何除了0和1之外的UINT取值都会使DoSomething产生异常。相反,CBClass只能接受两个枚举值中的一个。传递任何非法的常量都会使编译器报出错误或警告。
对比一下:
CAClass obj(1000, _T("This is a string"));
obj.DoSomething();
CBClass obj(1000, _T("This is a string));
obj.DoSomething();
在第一个例子中,CAClass obj(1000,_T(“This is a string”));将正常编译,并在运行时抛出异常。而第二个例子中,CBClass obj(1000, _T("This is a string));会毫不客气的在你的编译器里产生错误信息,这样就不会产生可执行文件,直到你纠正错误并提供合法值。
类CBClass的构造函数要求第一个参数的类型是constsOfInterestToThisClass,可以是bConstantOfInterestToThisClass1,也可以是bConstantOfInterestToThisClass2,还可以是constsOfInterestToThisClass类型的变量。编译器允许你定义constsOfInterestToThisClass型的变量,不过你给这个变量赋值的时候,只能使用你先前定义的枚举值。
constsOfInterestToThisClass var;
var = bConstantOfInterestToThisClass1; // OK
var = 47; // Error
结论:
编译器能够在编译的时候替你进行众多的错误检查,使用enum,而不是const,能够使编译器找到使用了不合适的假定条件的代码。