2009-11-15 132 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 
    }; 
}; 

我喜歡它,因爲理想,我會用一個命名空間來表示,它包含多個類的模塊,而不是僅僅作用域一個枚舉...