2009-11-15 94 views
5

我试图尽量保持本地的东西,所以我把枚举放在类范围内,即使它们是在两个类之间共享的(我把它放在类中“会更好”)。工作出色,但我最近遇到了一个问题,如果我把枚举放在类范围内,就会发生循环依赖。枚举范围问题

枚举将成为多个类的构造函数参数,它所在的类(以及最适合它的类)包含这些类。因此,不可能将enum用作包含类的构造函数参数,因为它会导致循环依赖。

将这个枚举放在它自己的头文件中会更好吗?如果是的话,我应该把头文件中的所有枚举都保持一致吗?有没有其他解决方案(这是合乎逻辑的)?

+0

你有没有试过转发声明? – 2009-11-15 17:59:45

+0

转发声明只允许您访问类型的名称。你不能访问接口或者实例化它或者做任何类似的事情。 – Anonymous 2009-11-15 18:02:38

回答

3

如果枚举被多个类的话,我会说,它并没有真正在一个类中的定义,但在命名空间属于这些班级在哪里居住。

这是除非枚举正在通过一个类传递给另一个类的构造函数,在这种情况下,它可能更有意义的实例化枚举相关类单独并作为参数传递给包含类的构造函数。

+0

您描述的第二件事是这种情况,但是您描述的方法不起作用。我决定只是在一个实用程序头文件中提供枚举数据,这个头文件具有常用的方法等。 – Anonymous 2009-11-15 18:19:42

-2

你可以尝试着声明这样的枚举:

enum MyEnum; 
+2

枚举不能被转发声明。 – Anonymous 2009-11-15 18:06:11

+1

即使你可以,你也不能转发声明嵌套类型。或者说,您不能在没有嵌套类型定义的情况下转发声明嵌套类型。 – 2009-11-15 19:57:18

+0

作为一个历史记录,既然C++ 11可以转发声明一个'enum class'(或'enum struct'),但它们不同于旧式'enum's。 – Quackmatic 2014-12-28 21:18:45

1

如果它是共享的,您应该将枚举放置在任何类之外,但是您仍然可以范围枚举。将其放置在命名空间,以便统计员不“漏”,塞满你的项目的命名空间:

namespace Project { // you already have this, right? :) 
    namespace COLOR { // naming styles differ, use what you like 
    enum Color { 
     red, 
     green, 
     blue 
    }; 
    } 
    using COLOR::Color; // now you can use the type 'normally' 

    // examples: 
    struct A { 
    Color c; 
    A() : c(COLOR::red) {} 
    }; 
    void f(Color c) { 
    using namespace COLOR; 
    // inside this function, we no longer have to prefix COLOR:: 
    if (c == green) { 
     go(); 
    } 
    else if (c == red) { 
     stop(); 
    } 
    } 
} 
+0

我必须尝试使用​​'using' s =声明,就像你做的一样,看看我是否比它更喜欢它我一直在使用的'typedef'混乱。我想我会喜欢它(但可能会使用与枚举类型的所有大小写不同的命名约定)。谢谢! – 2009-11-15 19:20:54

+0

我使用CAPS是因为它看起来Color会比COLOR :: red更多使用,或者你会经常使用后者,并且可以在函数作用域使用using-directive。 'typedef COLOR :: Color Color;'等同于'使用COLOR :: Color;'这里。 – 2009-11-15 20:35:47

2

我经常把我的枚举在命名空间中,以防止弄乱全局命名空间的各种枚举值。我认为这是你将它们放在课堂上所要做的。但是,如果他们没有在一类“适合”好,一个命名空间的工作原理非常简单,只是以及用于此目的:

namespace FooSettings 
{ 
    enum FooSettings 
    { 
     foo, 
     bar 
    }; 
} 
typedef enum FooSettings::FooSettings FooSettingsEnum; 


int main() 
{ 
    FooSettingsEnum x = FooSettings::foo; 
}; 

我有一个编辑片段,构建了赋予了新的枚举大纲只是它的名字,其中包括

typedef enum FooSettings::FooSettings FooSettingsEnum; 

创建typedef的行,因此使用枚举类型声明变量更具可读性。

我怀疑,如果Stroustrup有机会,他会将枚举值的名称作为枚举的范围,但是C兼容性强迫他的手(这只是猜测 - 也许有一天我会看D & E并看看如果他提到任何东西)。

+1

我个人更喜欢结构比命名空间,因为结构然后可以从模板中操作。 – 2009-11-16 12:15:29

+0

@Matthieu - 使用结构根本不会想到。我不能说我错过了不能使用模板来操作枚举,但我肯定没有看到使用结构来包装枚举作用域的缺点。还有一个好主意让我使用。谢谢。 – 2009-11-16 14:29:44

+0

我试图在命名空间和结构中封装枚举,并且有些事情对结构更好。所以我经常这样做: struct MyEnum {enum Values {a,b}; }; typedef MyEnum :: Values MyEnum_t; 现在我可以使用'MyEnum_t'来引用枚举作为类型,'MyEnum :: a','MyEnum :: b'来引用其成员,就好像枚举是聚合类型一样。在选择特定的命名约定之前,我尝试了一段时间,并且随着时间的推移,我发现上面的内容和我所能做的一样好。 – Permaquid 2010-01-08 21:25:02

7

我用的迈克尔·罗杰做一个变种:

namespace Color 
{ 
    enum Type 
    { 
     red, 
     green, 
     blue 
    }; 
}; 

void paintHouse(Color::Type color) {...} 

main() 
{ 
    paintHouse(Color::red); 
} 

我发现Color::Type要漂亮,更自我记录比Color::ColorCOLOR::Color。如果您发现Color::Type过于冗长,则可以使用Color::T

我不加前缀枚举值(即COLOR_RED),因为enum周围的名称空间实际上成为前缀。

我已经停止对我的作用域常量使用ALL_CAPS约定,因为它们与C库中的宏(例如NULL)发生冲突。宏都没有,只在定义的命名空间范围的

+0

我正在考虑采用Matthieu M的建议,使用struct而不是namespace来将它作为模板参数传递。然而,我想不出为什么我要通过Color而不是Color :: Type作为模板参数。 – 2010-01-08 19:12:11

11

由于C++ 11,你可以使用一个enum class(或enum struct - 同样,宣布不同的东西),其中枚举值被限定在枚举的名字。例如,这是一个有效的C++ 11声明。

enum class token_type { 
    open_paren, 
    close_paren, 
    identifier 
}; 

要访问值的枚举的,但是,你必须范围之正确使用::操作。因此,这是C++ 11的有效分配:

token_type type = token_type::close_paren; 

但是,这并不:

token_type type = close_paren; 

这解决了命名冲突,意味着你不必使用容器命名空间或结构只是为了阻止泄漏到他们不应该的位置的范围。这意味着下面的枚举可以在相同的范围形式存在token_type

enum class other_enum { 
    block, 
    thingy, 
    identifier 
}; 

现在这两个值称为在两个不同的结构identifier不会干涉。

1

我同意埃米尔。如果您使用的是C++ 98的另一种选择是使用结构,而不是命名空间,如下

struct Color 
{ 
    enum Type 
    { 
    red, 
    green, 
    blue 
    }; 
}; 

我喜欢它,因为理想,我会用一个命名空间来表示,它包含多个类的模块,而不是仅仅作用域一个枚举...