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


     在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:
    10     virtual void Func(enum Scope::EnumType type){}
    11 };
    12 
    13 class Derived: public Base
    14 {
    15 public:
    16     virtual void Func(enum EnumType type)
    17     {
    18         // Compiler can't catch the error even you compare 2 different enum types
    19         if(type == Scope::kType1) return;
    20     }
    21 };
    22 
    23 int main()
    24 {
    25     Scope::EnumType type = Scope::kType1;
    26     Base* pBase = new Derived();
    27     pBase->Func(type);
           delete pBase;

    28     return 0;
    29}

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

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

    1. 在C++中使用enum时,最好直接用类型名,而不是像C中那样加个enum的前缀,主要是放了防止意外的前置声明。
    2. VC++中的enum的前置声明是个好东西,应该加以利用 ,但使用时要显示的来用。 
  • 相关阅读:
    第一篇unity
    C#相关知识小结
    必须知道的八大种排序算法【java实现】
    JAVA八大排序算法
    二进制、八进制、十进制、十六进制之间的转换
    八大排序算法
    JSONArray数据转换成java List
    使用json-lib的JSONObject.toBean( )时碰到的日期属性转换的问题
    一探前端开发中的JS调试技巧
    SpringMVC注解说明
  • 原文地址:https://www.cnblogs.com/baiyanhuang/p/1853072.html
Copyright © 2020-2023  润新知