enum

本文介绍了C++中枚举类型的传统问题,如作用域冲突和隐式转换,然后重点讲解了C++11引入的枚举类(enumclass)如何解决这些问题,包括限定作用域、类型明确性和常量安全性。通过实例演示了如何使用enumclass避免命名冲突并指定存储类型。
摘要由CSDN通过智能技术生成

title: enum
date: 2021-06-21 11:25:27
tags: [C++]


enum

传统行为

枚举有如下问题:

  • 作用域不受限,,会容易引起命名冲突。例如下面无法编译通过的:
#include <iostream>
using namespace std;

enum Color {RED,BLUE};
enum Feeling {EXCITED,BLUE};

int main() 
{
    return 0;
}
  • 会隐式转换为 int。
  • 用来表征枚举变量的实际类型不能明确指定,从而无法支持枚举类型的前向声明。

经典做法

解决作用域不受限带来的命名冲突问题的一个简单方法是,给枚举变量命名时加前缀,如上面例子改成 COLOR_BLUE 以及 FEELING_BLUE。

一般说来,为了一致性我们会把所有常量统一加上前缀。但是这样定义枚举变量的代码就显得累赘。C 程序中可能不得不这样做。不过 C++ 程序员恐怕都不喜欢这种方法。替代方案是命名空间:

namespace Color 
{
    enum Type
    {
        RED=15,
        YELLOW,
        BLUE
    };
};

这样之后就可以用 Color::Type c = Color::RED; 来定义新的枚举变量了。如果 using namespace Color 后,前缀还可以省去,使得代码简化。不过,因为命名空间是可以随后被扩充内容的,所以它提供的作用域封闭性不高。在大项目中,还是有可能不同人给不同的东西起同样的枚举类型名。

更有效的办法是用一个类或结构体来限定其作用域,例如:定义新变量的方法和上面命名空间的相同。不过这样就不用担心类在别处被修改内容。这里用结构体而非类,是因为本身希望这些常量可以公开访问。

struct Color1
{
    enum Type
    {
        RED = 102,
        YELLOW,
        BLUE
    };
};
int main() {
    Color1 c1;
    cout << c1.RED << endl;

    Color1::Type c11 = Color1::BLUE;
    cout << c11 << endl;
    return 0;
}

C++11 的枚举类

上面的做法解决了第一个问题,但对于后两个仍无能为力。庆幸的是,C++11 标准中引入了枚举类(enum class),可以较好地解决上述问题。

  • 新的 enum 的作用域不在是全局的。
  • 不能隐式转换成其他类型。
enum class Color2
{
    RED = 2,
    YELLOW,
    BLUE
};
int main() {
    Color2 c2 = Color2::RED;
    cout << static_cast<int>(c2) << endl;
    return 0;
}
  • 可以指定用特定的类型来存储 enum。
enum class Color3 :char
{
    RED = 'r',
    BLUE
};
int main() {
    char c3 = static_cast<char>(Color3::RED);
    cout << c3 << endl;
    char c4 = static_cast<char>(Color3::BLUE);
    cout << c4 << endl;
    return 0;
}

类中的枚举类型

有时我们希望某些常量只在类中有效。 由于#define定义的宏常量是全局的,不能达到目的,于是想到实用 const 修饰数据成员来实现。而 const 数据成员的确是存在的,但其含义却不是我们所期望的。

const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其 const 数据成员的值可以不同。

不能在类声明中初始化 const 数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道 SIZE 的值是什么。

class A 
{
  const int SIZE = 100;   // 错误,企图在类声明中初始化 const 数据成员 
  int array[SIZE];  // 错误,未知的 SIZE 
}; 

const 数据成员应该在类的构造函数的初始化列表中进行初始化

class A 
{
  A(int size);  // 构造函数 
  const int SIZE ;    
}; 
A::A(int size) : SIZE(size)  // 构造函数的定义
{ 

} 
A  a(100); // 对象 a 的 SIZE 值为 100 
A  b(200); // 对象 b 的 SIZE 值为 200 

怎样才能建立在整个类中都恒定的常量呢?

别指望 const 数据成员了,应该用类中的枚举常量来实现。例如:

class Person {
public:
    enum {
        BOY = 0,
        GIRL
    };
};
int main() {
    cout << static_cast<int>(Person::BOY) << endl;
    cout << static_cast<int>(Person::GIRL) << endl;

    return 0;
}

枚举常量不会占用对象的存储空间,它们在编译时被全部求值

枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点。

PDF:链接 密码:dbm0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值