《深入理解C++11》笔记-强类型枚举

上一篇:《深入理解C++11》笔记-基于范围的for循环
本篇开始介绍第五章的内容:强类型枚举。
枚举enum的使用应该十分常见,用于定义同一类的数据。但是枚举其实存在一定的问题:

enum Male {
    Name, Age, Birthday
};

enum Female {
    Name, Age, Birthday
};

如上代码,如果两个枚举中定义了相同名称的枚举值,将会编译报错,因为枚举值并没有自己的名字空间。针对这种情况,往往会通过名字空间来分割枚举值的作用空间:

namespace Male{
    enum Male {
        Name, Age, Birthday
    };
}

namespace FeMale {
    enum Female {
        Name, Age, Birthday
    };
}

int main()
{
    int a = Male::Name;   // 使用时通过名字来决定使用哪个枚举值

    return 0;
}

另外,枚举值总是可以被隐式转换为整形,这也会引起一些问题:

enum Level {
    One,Two,Three,Four,Five
};

enum Type {
    Low,Medium,High
};

class Password {
public:
    Password(Level l, Type t) :level(l), type(t) {}
    Level level;
    Type type;
};

int main()
{
    Password pwd(One, Low);
    if (pwd.level < Medium)           // 原意是比较密码等级,但是比较了密码类型,编译器也不会报错
    {

    }

    return 0;
}

还有一点,枚举值所占用的空间大小也不确定。原来的标准规定,C++枚举的基础类型有编译器来具体制定实现,以下的代码输出是在Visual C++编译的:

enum A {A1 = 1, A2 = 2};
enum B { B1 = 1, B2 = 2, BMax = 0xFFFFFFF0U };
enum C { C1 = 1, C2 = 2, CMax = 0xFFFFFFFFFLL };

int main()
{
    std::cout << sizeof(A1) << std::endl;       // 4
    std::cout << sizeof(B1) << std::endl;       // 4
    std::cout << sizeof(BMax) << std::endl;     // 4
    std::cout << BMax << std::endl;             // -16,g++输出对应数值
    std::cout << sizeof(CMax) << std::endl;     // 4,g++输出8
    std::cout << CMax << std::endl;             // -1,g++输出对应数值

    return 0;
}

从上面的代码可以分析出,g++会在需要的时候将枚举扩展为8位,且会根据枚举的类型变动是否有符号。而Visual C++始终为4位,且始终为无符号类型。

强枚举类型

强枚举类型是C++11针对以上的问题引入的一种新的枚举类型:

enum class Type{              // 在enum后面加上class关键字
    Low,Medium,High
}

强枚举类型有几个特点:

  • 强作用域,必须制定枚举类型才能使用。
  • 转换限制,不能隐式转换为整形。
  • 底层类型,默认底层类型为int,能够显式指定底层类型。
enum class Type : char{              // 指定类型
    Low,Medium,High
}

下面我们看一下强枚举类型的具体例子:

enum class Level {
    One,Two,Three,Four,Five
};

enum class Type {
    Low,Medium,High
};

class Password {
public:
    Password(Level l, Type t) :level(l), type(t) {}
    Level level;
    Type type;
};

int main()
{
    Password pwd(One, Low);         // 编译失败,必须使用枚举类型名字
    Password pwd(Level::One, Type::Low);

    if (pwd.level < Type::Medium)   // 编译失败,必须使用同一枚举类型进行比较
    {
    }

    if (pwd.level < Level::Three)
    {
    }

    if (pwd.type > 1)               // 编译失败,无法隐式转换为整形
    {
    }

    if ((int)pwd.type > 1)
    {
    }

    return 0;
}

另外,指定基本类型之后,各个编译器之间的实现就会相同,便于代码移植:

enum class B : unsigned int{ B1 = 1, B2 = 2, BMax = 0xFFFFFFF0U };

int main()
{
    std::cout << sizeof(B::B1) << std::endl;       // 4
    std::cout << sizeof(B::BMax) << std::endl;     // 4
    std::cout << (unsigned int)B::BMax << std::endl; // 4294967280

    return 0;
}

下一篇:深入理解C++11》笔记-智能指针unique_ptr、shared_ptr、weak_ptr

猜你喜欢

转载自blog.csdn.net/wizardtoh/article/details/81010433