【问题标题】: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 枚举。这样,至少,我们明确了我们所指的枚举。)

【问题讨论】:

    标签: c++ class enums namespaces scope


    【解决方案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))
                 )
    

    一些参考资料:

    1. Herb Sutter,Jum Hyslop,C/C++ 用户杂志,22(5),2004 年 5 月
    2. 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 这正是你想要的。

    【讨论】:

    【解决方案3】:

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

    enum Color
    {
      Clr_Red,
      Clr_Yellow,
      Clr_Blue,
    };
    

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

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

    • 命名空间
    • 结构/类

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

    操纵示例包括:

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

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

    【讨论】:

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

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

      【讨论】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        相关资源
        最近更新 更多