C++ 中的枚举类型继承于 C 语言。就像其他从 C 语言继承过来的很多特性一样,C++ 枚举也有缺点,这其中最显著的莫过于作用域问题——在枚举类型中定义的常量,属于定义枚举的作用域,而不属于这个枚举类型。例如下面的示例:

enum FileAccess {
    Read = 0x1,
    Write = 0x2,
};

FileAccess access = ::Read; // 正确
FileAccess access = FileAccess::Read; // 错误

C++枚举的这个特点对于习惯面向对象和作用域概念的人来说是不可接受的。首先,FileAccess::Read 显然更加符合程序员的直觉,因为上面的枚举定义理应等价于如下的定义(实际上,.NET 中的枚举类型便是如此实现的):

class FileAccess {
    static const int Read = 0x1;
    static const int Write = 0x2;
};

其次,这导致我们无法在同一个作用域中定义两个同样名称的枚举值。也就是说,以下的代码是编译错误:

enum FileAccess {
    Read = 0x1,
    Write = 0x2,
};

enum FileShare {
    Read = 0x1, // 重定义
    Write = 0x2, // 重定义
};

如果这一点没有让你恼怒过的话,你可能还没写过多少 C++ 代码 :-)。实际上,在最新的 C++0x 标准草案中有关于枚举作用域问题的提案,但最终的解决方案会是怎样的就无法未卜先知了,毕竟对于象 C++ 这样使用广泛的语言来说,任何特性的增删和修改都必须十分小心谨慎。

当然,我们可以使用一些迂回的方法来解决这个问题(C++ 总是能给我们很多惊喜和意外)。例如,我们可以把枚举值放在一个结构里,并使用运算符重载来逼近枚举的特性:

struct FileAccess {
    enum __Enum {
        Read = 0x1,
        Write = 0x2
    };
    __Enum _value; // 枚举值

    FileAccess(int value = 0) : _value((__Enum)value) {}
    FileAccess& operator=(int value) {
        this->_value = (__Enum)value;
        return *this;
    }
    operator int() const {
        return this->_value;
    }
};

我们现在可以按照希望的方式使用这个枚举类型:

FileAccess access = FileAccess::Read;

并且,因为我们提供了到 int 类型的转换运算符,因此在需要 int 的地方都可以使用它,例如 switch 语句:

switch (access) {
    case FileAccess::Read:
        break;
    case FileAccess::Write:
        break;
}

当然我们不愿意每次都手工编写这样的结构。通过使用宏,我们可以很容易做到这一点:

#define DECLARE_ENUM(E) /
struct E /
{ /
public: /
    E(int value = 0) : _value((__Enum)value) { /
    } /
    E& operator=(int value) { /
        this->_value = (__Enum)value; /
        return *this; /
    } /
    operator int() const { /
        return this->_value; /
    } /
/
    enum __Enum {

#define END_ENUM() /
    }; /
/
private: /
    __Enum _value; /
};

我们现在可以按如下的方式定义前面的枚举,并且不比直接写 enum 复杂多少。

DECLARE_ENUM(FileAccess)
    Read = 0x1,
    Write = 0x2,
END_ENUM()

DECLARE_ENUM(FileShare)
    Read = 0x1,
    Write = 0x2,
END_ENUM()

C++ enum 作用域问题和解决方案的更多相关文章

  1. js常见问题之为什么点击弹出的i总是最后一个

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. C# 类中访问修饰符的优先级与用法(public, internal, protected, private)

    首先:类成员的访问级别是以类的访问级别为上限的! 也就是类的访问级别低时,类成员的访问级别高也无法突破类的访问级别 public级别,作用域是这个解决方案() internal级别,作用域是整个装配集 ...

  3. 非法字符: '\ufeff' 解决方案|错误: 需要class, interface或enum

    解决方案,把文件用Editplus打开,UTF-8+BOM编码的文件转为普通的UTF-8文件

  4. 错误: 非法字符: '\ufeff' 解决方案|错误: 需要class, interface或enum

    解决方案,把文件用Editplus打开,UTF-8+BOM编码的文件转为普通的UTF-8文件

  5. Vue style里面使用@import引入外部css, 作用域是全局的解决方案

    问题描述 使用@import引入外部css,作用域却是全局的 <template> </template> <script> export default { na ...

  6. 解决编译错误: 非法字符: '\ufeff' 解决方案|错误: 需要class, interface或enum

    http://www.cnblogs.com/oymx/p/5353235.html 可以 note++打开  在格式里  选择utf-8 无bom格式编码 即可

  7. VC ADO “ParameterDirectionEnum”:“enum” 类型等 重定义问题 解决方案

    原因分析: 1.在头文件中: #import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace ...

  8. 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define

    其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...

  9. C#进阶系列——WebApi 异常处理解决方案

    前言:上篇C#进阶系列——WebApi接口传参不再困惑:传参详解介绍了WebApi参数的传递,这篇来看看WebApi里面异常的处理.关于异常处理,作为程序员的我们肯定不陌生,记得在介绍 AOP 的时候 ...

随机推荐

  1. HDU Exponentiation 1063 Java大数题解

    Exponentiation Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  2. go-vim配置

    一.环境准备: 系统环境说明: [root@docker golang]# cat /etc/redhat-release CentOS Linux release (Core) [root@dock ...

  3. 你应该知道CSS选择器技巧

    什么是:before和:after? 该如何使用他们? :before是css中的一种伪元素,可用于在某个元素之前插入某些内容. :after是css中的一种伪元素,可用于在某个元素之后插入某些内容. ...

  4. 初识eclipse及配置相关

    1. Eclipse 导入外部项目无法识别为Web项目并无法再部署到tomcat解决办法: http://www.cnblogs.com/heshan664754022/archive/2013/05 ...

  5. log4j.xml配置示例

    这是log4j1.x版本讲解,log4j-1.2.16.jar    1. 一般的log4j.xml的两种配置方式: 1.Logger 完成日志信息的处理定义输出的层次和决定信息是否输出DEBUG&l ...

  6. linux vim taglist config

    "vim config .vimrc "taglist map <silent> <F10> :TlistToggle let tlist_php_sett ...

  7. Expression Language

    EL找不到属性会返回"" page –-  request --- session --- application ------------------------------- ...

  8. 星际SC 地图 Big Game Fort 要塞之战 修正了 BIG GAME 地图的平衡性

    星际SC 地图 Big Game Fort 要塞之战 修正了 BIG GAME 地图的平衡性 也适合BIG 1V1 对战 此版本目前不开放1打1造功能

  9. hdu 4545 魔法串 2013金山西山居创意游戏程序挑战赛——初赛(1)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4545 这题太坑了,小明的串可以任意删掉某个字符 这句话不知道大家是怎么理解的,我觉得应该是能够删除其中 ...

  10. java 线程学习

    转载:详见处http://lavasoft.blog.51cto.com/62575/27069   Java多线程编程总结   下面是Java线程系列博文的一个编目:   Java线程:概念与原理 ...