在一个类中声明一个枚举


150

在以下代码段中,ColorCar类内声明了枚举,以限制枚举的范围,并尝试不“污染”全局名称空间。

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-tr​​icks-2-better-enums

(2)在此示例中,当类中工作时,最好将枚举编码为Car::Color,还是就Color足够了?(我假设前者比较好,以防万一Color在全局名称空间中声明了另一个枚举。至少,这样,我们明确了我们要引用的枚举。)

Answers:


85
  1. 如果Color是特定于Cars的东西,那么这就是限制其范围的方式。如果您将拥有另一个供Color其他类使用的枚举,则最好将其设为全局(或至少是outside Car)。

  2. 没有什么不同的。如果有一个全局范围,那么仍将使用本地范围,因为它离当前范围较近。请注意,如果您在类定义之外定义那些函数,则需要Car::Color在函数的界面中显式指定。


12
2.是和否。Car::Color getColor()但是void Car::setColor(Color c)因为setColor我们已经有了说明符。
Matthieu M.


66

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

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 Stronged Type Enums(修订版3),2007年7月

我喜欢这个。它还会强制使用有效值实例化枚举。我确实认为赋值运算符和复制构造函数将很有用。而且t_应该是私有的。我不能没有的宏。
jmucchiello,2010年

我也喜欢这样 感谢您的参考。
anio

1
您说:“它的类型安全性也要高得多(您不能分配甚至比较两个不同的枚举……”。为什么您认为它是一个好功能?我认为这if(c2 == Color::Red )是合理的,必须进行编译,但是在您的示例中,它是可编译的。同样的论据也可以转让!
Nawaz

3
@Nawaz c2是另一种类型(Color2),那么您为什么认为c2 == Color::Red应该编译分配?如果Color::Red是1,Color2::Red是2怎么办?应该Color::Red == Color2::Red评估为true还是false?如果您混合使用非类型安全的枚举数,那么您将会遇到麻烦。
维克多·K

2
为什么不是类型t_; 私人的?
Zingam

7

通常,我总是将枚举放在一个struct。我已经看到了包括“前缀”在内的一些准则。

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

一直以为这看起来更像是C指南,而不是指南C++(之所以这样是因为它的缩写,也因为中的名称空间C++)。

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

  • 命名空间
  • 结构/类

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

操作示例包括:

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

它返回struct中的enum的元素数T:)


3

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.