在类中声明一个枚举

Posted

技术标签:

【中文标题】在类中声明一个枚举【英文标题】:Declaring an enum within a class 【发布时间】:2011-01-31 00:30:24 【问题描述】:

在下面的代码 sn-p 中,Color 枚举在 Car 类中声明,以限制枚举的范围并尽量不“污染”全局命名空间。

class Car

public:

   enum Color
   
      RED,
      BLUE,
      WHITE
   ;

   void SetColor( Car::Color color )
   
      _color = color;
   

   Car::Color GetColor() const
   
      return _color;
   

private:

   Car::Color _color;

;

(1) 这是限制Color 枚举范围的好方法吗?或者,我应该在 Car 类之外声明它,但可能在它自己的命名空间或结构中?我今天刚看到这篇文章,它提倡后者并讨论了一些关于枚举的好点:http://gamesfromwithin.com/stupid-c-tricks-2-better-enums。

(2) 在本例中,当类中工作时,最好将枚举编码为Car::Color,还是只使用Color 就足够了? (我认为前者更好,以防万一在全局命名空间中声明了另一个 Color 枚举。这样,至少,我们明确了我们所指的枚举。)

【问题讨论】:

【参考方案1】:

我更喜欢以下方法(代码如下)。 它解决了“命名空间污染”问题,但它也更加类型安全(你不能分配甚至比较两个不同的枚举,或者你的枚举与任何其他内置类型等)。

struct Color

    enum Type
    
        Red, Green, Black
    ;
    Type t_;
    Color(Type t) : t_(t) 
    operator Type () const return t_;
private:
   //prevent automatic conversion for any other built-in types such as bool, int, etc
   template<typename T>
    operator T () const;
;

用法:

Color c = Color::Red;
switch(c)

   case Color::Red:
     //некоторый код
   break;

Color2 c2 = Color2::Green;
c2 = c; //error
c2 = 3; //error
if (c2 == Color::Red )  //error
If (c2)  error

我创建宏以方便使用:

#define DEFINE_SIMPLE_ENUM(EnumName, seq) \
struct EnumName \
   enum type \
    \
      BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\
   ; \
   type v; \
   EnumName(type v) : v(v)  \
   operator type() const return v; \
private: \
    template<typename T> \
    operator T () const;;\

#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \
    BOOST_PP_TUPLE_ELEM(2, 0, record) = BOOST_PP_TUPLE_ELEM(2, 1, record),

用法:

DEFINE_SIMPLE_ENUM(Color,
             ((Red, 1))
             ((Green, 3))
             )

一些参考资料:

    Herb Sutter,Jum Hyslop,C/C++ 用户杂志,22(5),2004 年 5 月 Herb Sutter、David E. Miller、Bjarne Stroustrup 强类型枚举(修订版 3),2007 年 7 月

【讨论】:

我喜欢这个。它还强制使用有效值实例化枚举。我确实认为赋值运算符和复制构造函数会很有用。 t_ 也应该是私有的。我可以不用的宏。 我也喜欢这个。感谢您的参考。 你说:“而且它的类型安全性更高(你不能分配甚至比较两个不同的枚举......”。你为什么认为它是一个好功能?我认为if(c2 == Color::Red ) 是合理的,必须编译,但在你的例子中它没有。同样的赋值参数! @Nawaz c2 是另一种类型 (Color2),那么您为什么认为 c2 == Color::Red 和作业应该编译?如果Color::Red 是1,而Color2::Red 是2 会怎样? Color::Red == Color2::Red 应该评估为 true 还是 false?如果你混合使用非类型安全的枚举器,你会很糟糕。 为什么不是类型 t_;私人的?【参考方案2】:

现在 - 使用 C++11 - 你可以使用 enum class 来做这个:

enum class Color  RED, BLUE, WHITE ;

AFAII 这正是你想要的。

【讨论】:

遗憾的是,它不允许成员函数:***.com/a/53284026/7395227【参考方案3】:

一般来说,我总是将我的枚举放在struct 中。我看过一些指南,包括“前缀”。

enum Color

  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
;

一直认为这看起来更像 C 指南而不是 C++ 指南(一方面是因为缩写,也因为 C++ 中的命名空间)。

因此,为了限制范围,我们现在有两种选择:

命名空间 结构/类

我个人倾向于使用struct,因为它可以用作模板编程的参数,而不能操作命名空间。

操纵示例包括:

template <class T>
size_t number()  /**/ 

它返回结构体T 中枚举元素的数量:)

【讨论】:

【参考方案4】:

    如果 Color 是特定于 Cars 的东西,那么这就是限制其范围的方式。如果您要拥有另一个其他类使用的 Color 枚举,那么您不妨将其设为全局(或至少在 Car 之外)。

    没有区别。如果有一个全局的,那么仍然使用本地的,因为它更接近当前范围。请注意,如果您在类定义之外定义这些函数,则需要在函数的接口中显式指定 Car::Color

【讨论】:

2.是和不是。 Car::Color getColor()void Car::setColor(Color c) 因为在 setColor 我们已经有了说明符。【参考方案5】:

如果您正在创建代码库,那么我将使用命名空间。但是,您仍然只能在该命名空间内拥有一个 Color 枚举。如果您需要一个可能使用通用名称的枚举,但可能对不同的类有不同的常量,请使用您的方法。

【讨论】:

以上是关于在类中声明一个枚举的主要内容,如果未能解决你的问题,请参考以下文章

在类中声明一个自动 lambda 函数

在类中声明装饰器

在类中声明结构

在类中声明第一个字段属性之前添加额外的行

在类中使用未声明的标识符

使用“接口”时在类中没有声明成员函数