美文网首页
enum class

enum class

作者: ColdWave | 来源:发表于2018-08-25 17:33 被阅读0次

    强类型枚举

    枚举:分门别类与数值的名字

    enum Gender {
        Male,   // 默认设置为0
        FeMale  // 默认设置为1
    };
    
    enum {
        Male,
        FeMale
    };
    
    #define Male 0
    #define FeMale 1
    
    // C++ 推荐的方式, 静态常量作用域可以被限制在文件内,但是会增加存储空间
    const static int Male = 0;
    const static int FeMale = 1;
    

    允许匿名枚举的出现容易出现以下问题:

    enum Type { General, Light, Medium, Heavy };
    enum Category { General, Pistol, MachineGun, Cannon };
    // 出现了全局名字
    
    #include <iostream>
    
    namespace T {
        enum Type { General, Light, Medium, Heavy };
    };
    
    // 匿名 namespace, Category 会默认进入全局命名空间
    namespace {
        enum Category { General, Pistol, MachineGun, Cannon };
    };
    
    int main() {
        T::Type t = T::Light;
        if (t == General) // 忘记使用 namespace
            std::cout << "General Weapon" << std::endl;
        return 0;
    }
    
    • C语言中枚举是 常量数值的 别名,因此会被隐式转换为整形。这是不安全的。
    #include <iostream>
    using namespace std;
    
    enum Type { General, Light, Medium, Heavy };
    // enum Category { General, Pistol, MachineGun, Cannon }; // error, 重复定义
    enum Category { Pistol, MachineGun, Cannon };
    
    struct Killer {
        Killer(Type t, Category c) : type(t), category(c) {}
        Type type;
        Category category;
    };
    
    int main()
    {
        Killer cool(General, MachineGun);
        // ......
        if (cool.type >= Pistol) {
            std::cout << "It is not a pistol" << std::endl;
        }
    
        // ...
        std::cout << is_pod<Type>::value << std::endl; // 1
        std::cout << is_pos<Category>::value << std::endl; // 1
    
        return 0;
    }
    

    为了解决上述问题,需要对 enum 进行封装.

    #include <iostream>
    
    class Type {
    public:
        enum type { general, light, medium, heavy };
        type val;
    public:
        Type(type t) : val(t) {}
        bool operator >= (const Type &t) { return val >= t.val; }
        static const Type General, Light, Medium, Heavy;
    };
    
    const Type Type::General(Type::general);
    const Type Type::Light(Type::light);
    const Type Type::Medium(Type::medium);
    const Type Type::Heavy(Type::heavy);
    
    class Category {
    public:
        enum category { pistol, machineGun, cannon };
        category val;
    
    public:
        Category(category c) : val(c) {}
        bool operator >= (const Category &c) { return val >= c.val; }
        static const Category Pistol, MachineGun, Cannon;
    };
    
    const Category Category::Pistol(Category::pistol);
    const Category Category::MachineGun(Category::machineGun);
    const Category Category::Cannon(Category::cannon);
    
    struct Killer {
        Killer(Type t, Category c) : type(t), category(c) {}
        Type type;
        Category category;
    };
    
    int main(int argc, char *argv[])
    {
        // 使用类型包装后的 enum
        Killer notCool(Type::General, Category::MachineGun);
        // ......
        if (notCool.type >= Type::General) {
            std::cout << "It is not general" << std::endl;
        }
    //    if (notCool.type >= Category::Pistol) {  // error
    //        std::cout << "It is not a pistol" << std::endl;
    //    }
    
        std::cout << std::is_pod<Type>::value << std::endl; // 0
        std::cout << std::is_pod<Category>::value << std::endl; // 0
    
        return 0;
    }
    

    缺点:

    • 复杂
    • POD 的 enum 被封装成 非 POD
    • 大多数系统的ABI规定,传递参数的时候如果参数是一个结构体,就不能使用寄存器来传参。而整形可以使用寄存器传递。所以可能会有性能上的损失。
    #include <iostream>
    
    enum C { C1 = 1, C2 = 2};
    enum D { D1 = 1, D2 = 2, Dbig = 0xFFFFFFF0U };
    enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFFFFLL };
    
    int main(int argc, char *argv[])
    {
        std::cout << sizeof(C1) << std::endl; // 4
    
        std::cout << Dbig << std::endl;         // 4294967280
        std::cout << sizeof(D1) << std::endl;   // 4
        std::cout << sizeof(Dbig) << std::endl; // 4
    
        std::cout << Ebig << std::endl;         // 68719476735
        std::cout << sizeof(E1) << std::endl;   // 8
    
        return 0;
    }
    
    • 编译器会根据 enum 的数值,对 enum 数据长度进行扩展。

    强类型枚举以及C++11对原有枚举类型的扩展

    弱枚举类型的作用域,隐式转换,占用存储空间的不确定都是枚举类的缺点。

    针对上述缺点,C++11 引入了强枚举类型。(strong-typed enum)

    enum class Type { General, Light, Medium, Heavy };
    
    • 强作用域:强类型枚举成员的名称不会被输出到其父作用域空间。
    • 转换限制: 强类型枚举成员的值不可以与整型隐式的互相转换。
    • 可以指定底层类型。默认类型是 int, 但也可以显式的指定类型。type 可以是除 wchar_t 以外的任何整型。
    enum class Type : char { General, Light, Medium, Heavy };
    
    #include <iostream>
    
    enum class Type { General, Light, Medium, Heavy };
    enum class Category { General = 1, Pistol, MachinGun, Cannon };
    
    int main(int argc, char *argv[])
    {
        Type t = Type::Light;
        t = General;            // error
        if (t == Category::General) { // error,无法比较
            // ...
        }
        if (t > Type::General) { // ok
            // ...
        }
        if (t > 0) { // error, 不可以隐式转换
            // ...
        }
        if ((int)t > 0) { // ok
            // ...
        }
    
        std::cout << std::is_pod<Type>::value << std::endl;     // 1
        std::cout << std::is_pod<Category>::value << std::endl; // 1
    
        return 0;
    }
    
    • 匿名 enum class
    enum class { General, Light, Medium, Heavy } weapon;
    
    int main()
    {
        weapon = General;   // error
        bool b = (weapon == weapon::General); // error
    
        return 0;
    }
    

    因为是强作用域,所以 匿名 enum class 啥都做不了.

    相关文章

      网友评论

          本文标题:enum class

          本文链接:https://www.haomeiwen.com/subject/enpgiftx.html