您的位置:首页 > 其它

枚举和前置声明以及可能引起的问题

2010-10-16 15:03 190 查看

在VC++ 2008下编译如下代码:

void func(enum EnumType type)

{

//......

}

int main()

{

EnumType type = (EnumType)0;

func(type);

return 0;

}
你会发现这段代码可以成功的编译并且运行,但是如果你足够细心,应该会发现EnumType并没有被定义,为什么使用没有定义的类型却能正常编译甚至运行呢?

原因有二:

1. 函数中的参数声明enum EnumType type,不但被解析为一个参数声明,也被解析为对EnumType的一个前置声明。
其实不光对enum,对class也是一样,比如

void func(class Base b)

{

//......

}

也是没有问题的,这里在声明函数参数的同时,因为加了class这个关键词,也达到了前置声明calss Base的效果。

2. VC++的扩展对enum的前置声明的支持。
我们知道,C++标准其实是不支持enum的前置声明的,原因在于标准规定Enum的size是由其所容纳的值所确定的,所以在看到所有的值之前,编译器是无法确定其存储的。在这篇讨论中可以得到很多信息。而在VC++实现中,确定enum的size为4个字节,从而使Enum的前置声明成为可能 --- 不得不说,我认为这是VC++不同于标准,却又高于标准的实现。

所以以上代码其实是前置声明并使用了EnumType,因为并没有设计到EnumType的具体的枚举值,所以使用并没有任何问题 --- 毕竟,Enum是个4字节的整型数而已。

我们知道,在C中,当我们使用一个定义好的enum时(struct也一样),我们需要在定义的类型前加上前缀enum ,而不是直接使用该类型,比如前面的EnumType, 我们应该以enum EnumType的方式来使用,但在C++中,这个限制不再存在,但是这种用法被保留了下来。所以我们可以看到在不少地方大家还是会这么用。这就为引入问题提供了方便:

你以为你在使用你定义的那个enum,其实你只是在使用你自己前置声明的那个而已


举个我在现实项目中遇到的问题,看如下代码:

1 class Scope
2 {
3 public:
4 enum EnumType {kType1, kType2};
5 };
6
7 class Base
8 {
9 public:
virtual void Func(enum Scope::EnumType type){} };

class Derived: public Base
{
public:
virtual void Func(enum EnumType type)
{
// Compiler can't catch the error even you compare 2 different enum types
if(type == Scope::kType1) return;
}
};

int main()
{
Scope::EnumType type = Scope::kType1;
Base* pBase = new Derived();
pBase->Func(type);
delete pBase;28 return 0;
}

这里试图在Derived中重载Base中的Func虚函数, 但是在声明参数的时候用了enum EnumType,而不是enum Scope::EnumType,而编译器不会报错。但事实上, 这里是直接前置声明了一个与Scope::EnumType截然不同的枚举类型EnumType,结果是Derived::Func永远也不会被调到,因为它根本就不是个虚函数Base::Func的重载。

了解了这些,我的对使用Enum的建议是:

在C++中使用enum时,最好直接用类型名,而不是像C中那样加个enum的前缀,主要是放了防止意外的前置声明。
VC++中的enum的前置声明是个好东西,应该加以利用 ,但使用时要显示的来用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐