c++ 枚举值的行为是否类似于全局变量?

4nkexdtk  于 2023-02-20  发布在  其他
关注(0)|答案(7)|浏览(273)

我有两个枚举,如果一个枚举中的一个值与另一个枚举中的一个值同名:

enum A {joe, bob, doc};
enum B {sunday, monday, doc};

编译器(Visual Studio的)抱怨重定义了doc,这意味着它将其视为全局变量。是这样吗?这不是我所期望的行为,它迫使我管理项目中所有枚举元素的名称。
任何见解都会有所帮助。

wydwbb8l

wydwbb8l1#

它不被当作一个全局变量,而是一个全局标识符。
更准确地说,它在声明enum的任何名称空间中都被视为标识符。在您的示例中,这是全局名称空间。
要了解全局标识符和全局变量之间的区别,请尝试获取枚举的地址。)
通常当我定义枚举时,我会在前面加上标识符名称的缩写版本,如下所示:

enum InstrumentType { itStock, itEquityOption, itFutureOption };

这有助于避免碰撞。

v1l68za4

v1l68za42#

怀亚特·安德森已经提出

namespace A
{
    enum A {joe, bob, doc};
}
namespace B
{
    enum B {sunday, monday, doc};
}

作为对“枚举值与枚举本身在同一作用域中”问题的修复,允许您编写

A::doc;
B::doc;

但是,当您希望enum局部于类时,这种解决方案是不可用的,至少在类外部不引入人工命名空间的情况下是不可用的。
一个简单的解决方案是将每个enum Package 在一个结构体中,如下所示:

struct A
{
    enum Enum {joe, bob, doc};
};
struct B
{
    enum Enum {sunday, monday, doc};
};

这允许使用与名称空间解决方案相同的用法表示法,

A::doc;
B::doc;

而且还允许

  • 类中的定义,
  • 通过继承将枚举名直接带入类中,以及
  • 通过typedef对限定符进行本地类重命名。

另外,上面举例说明的 * 命名约定 * 允许

  • 在我看来,在引用枚举类型时需要额外的澄清,例如编写A::Enum

好的,命名约定也可以用于基于命名空间的解决方案......
干杯,

oug3syen

oug3syen3#

C++03中的枚举器与枚举有相同的作用域。

enum     xxx    {    yyy,       zzz       };
          ^           ^          ^ 
    enumeration    enumerator enumerator

这有时很方便,有时却不太方便。
在C++0x中,我们有enum class,它更像C#的enums,同时,假设(因为这是语言规则)yyyzzzxxx有完全相同的作用域

3qpi33ja

3qpi33ja4#

如果你想让它们成为全局的,通过把你的enum扔到一个命名空间中来解决你的问题并避免命名空间污染:

namespace A
{
    enum A {joe, bob, doc};
}
namespace B
{
    enum B {sunday, monday, doc};
}

A::doc;
B::doc;
e3bfsja2

e3bfsja25#

枚举的值存在于声明enum的任何作用域中。
例如,下面的工作原理是:

enum A {joe, bob, doc};
namespace C { enum B {sunday, monday, doc}; }

class A_class { enum A {joe, bob, doc}; };
class B_class { enum B {sunday, monday, doc}; };
dwbf0jvd

dwbf0jvd6#

枚举的值具有枚举本身的作用域,即它的声明作用域。例如:

enum A {value = 30};

int main()
{
   enum B {value = 32};
   int x = value;
}

x将是32。

zqdjd7g9

zqdjd7g97#

假设我们想要声明一个图形窗口的长宽比,然后按照前面的建议定义枚举值:

struct __aspect_ratio__
{
    enum values
    {
        ASPECT_RATIO_16_9,  // HD video
        ASPECT_RATIO_16_2,  // *for testing purposes*
        ASPECT_RATIO_4_3,   // standard monitor
        ASPECT_RATIO_3_2,   // classic film
        ASPECT_RATIO_21_9,  // cinemascope
        ASPECT_RATIO_1_1    // quadratic window
    };
};

typedef __aspect_ratio__::values AspectRatio;

最后的typedef允许我们使用AspectRatio::ASPECT_RATIO_16_9作为简写,例如函数签名:

void SetAspectRatio(AspectRatio aspect)
{
    switch(aspect)
    {
    case AspectRatio::ASPECT_RATIO_16_9:
    // ...
    default:
            std::cerr << "Undefined aspect ratio enum value!" << std::endl;
        }
    }
}

这对我来说就像我在C#中所期望的那样。

编辑:

假设您使用的是至少C++11,那么最好声明一个enum class

enum class values
{
    AspectRatio_16_9,  // HD video
    AspectRatio_16_2,  // *for testing purposes*
    AspectRatio_4_3,   // standard monitor
    AspectRatio_3_2,   // classic film
    AspectRatio_21_9,  // cinemascope
    AspectRatio_1_1    // quadratic window
};

这是一个类型安全的替代方法,不会污染封闭作用域,还需要注意的是,为了防止名称与全局定义的宏冲突,enum class值通常不应该使用ALL_CAPS命名约定。

相关问题