2013-03-01 71 views
6

我知道只有靜態,常量和int/enum(pre C++ 11)的數據成員才能在類聲明中初始化。 「所有其他靜態數據成員都必須在全局命名空間範圍內定義(即在類定義的主體之外),並且只能在這些定義中初始化」。爲什麼非const,非int/enum靜態數據成員必須在定義之外進行初始化?

爲什麼其他靜態數據成員不能在類定義中初始化?這是被禁止的具體原因嗎?

如果數據成員是特定於類的,爲什麼它們在全局命名空間範圍內聲明,而不是某些與其類相關的範圍?

+2

「全局命名空間範圍」具有誤導性 - 定義發生在實際類的名稱空間範圍內;不是全局命名空間的範圍。 (正如我在答案中所示) – 2013-03-01 21:47:53

回答

5

爲什麼其他靜態數據成員不能在類定義中初始化?這是被禁止的具體原因嗎?

很可能是因爲C++有單獨的翻譯單元。編譯器需要選擇一個將放置這些符號的初始化邏輯的對象文件。強制這個在特定的源文件中,這使得編譯器的決定變得容易。

如果數據成員是特定於類的,爲什麼它們在全局命名空間範圍內聲明,而不是某些與其類相關的範圍?

因爲這就是C++的類成員。這並不比其他類成員一樣的成員函數不同:

頭文件

namespace example { 

// Class declared in header 
struct some_class 
{ 
    // Member variable 
    static float example; 
    // Member function 
    void DoStuff() const; 
}; 

} 

源文件:

namespace example { 

    // Implement member variable 
    float some_class::example = 3.14159; 
    // Implement member function 
    void some_class::DoStuff() const 
    { 
     //.... 
    } 
} 

有一個特定的異常,讓靜態常量組成成員的初始化因爲它允許編譯器將它們視爲編譯時常量。也就是說,您可以使用它們來定義類定義中的數組或其他類似位的大小。

+0

我認爲你的最後一段是我第一個問題的答案?另外,你是說「全局命名空間範圍」實際上是指所討論的類/結構的「全局命名空間範圍」?這不是真正的GLOBAL命名空間....? – user997112 2013-03-01 21:58:02

+0

@user:是的。最後的註釋「(即在類定義的主體之外)」正在解決真正意義上的問題 - 只需要在某個地方定義一個定義即可。 – 2013-03-01 22:00:11

-1

每次該類被實例化時,它們都會被重新初始化。每次創建一個Foo類型的新對象時,所有Foos的靜態變量都將重置爲其初始值,這可能不是您想要的。因此,如果你想在你的對象中使用靜態變量,它們要麼a)不能改變它們的值,這意味着將它們重新初始化爲相同的值是安全的,或者b)只能在初始化函數的上下文之外改變。

+1

這沒有任何意義。爲什麼當每個實例被實例化時都會發生靜態成員的初始化? – 2013-03-01 21:49:25

4

爲什麼其他靜態數據成員不能在類定義中初始化?這是被禁止的具體原因嗎?

通常,所有靜態對象都需要在一個單獨的翻譯單元中定義,以便它們具有定義明確的地址。作爲一個特殊的例外,靜態,常量,非易失類成員不需要定義如果其地址不是必需的,並且它們具有足夠簡單的類型,以便它們的值可以被編譯時常量替換。

從歷史上看,「足夠簡單」被定義爲整數或枚舉類型; C++ 11將其擴展爲包含具有constexpr說明符的任何文字類型。

如果數據成員是特定於類的,爲什麼它們在全局命名空間範圍內聲明,而不是某些與其類相關的範圍?

它們沒有在全局命名空間範圍內聲明。他們在課堂上被宣佈和確定範圍。

如果你的意思是,他們爲什麼在類定義之外定義了,這是因爲在整個程序中必須只有一個靜態成員的定義;但該類必須在使用它的每個翻譯單元中定義。

+0

+1。當然,他們想出了一些內聯函數(你可以把它的地址),大概他們可以使用相同的機制。 – 2013-03-01 22:01:02

+0

@BillyONeal:確實可以。但他們沒有。 – 2013-03-01 22:01:51

2

爲什麼其他靜態數據成員不能在類 定義中初始化?這是被禁止的具體原因嗎?

靜態數據成員在很多方面(特別是從編譯器的角度來看)類似於具有外部鏈接的名稱空間範圍數據對象。

靜態數據成員的聲明只是一個聲明,而不是一個定義。它類似於一個全局對象的extern聲明,並且必須包含在可能使用該對象的任何翻譯單元中。

定義必須出現在一個翻譯單元中,並且這是初始化表達式所屬的位置。除非一個表達符合常量表達式的嚴格標準,否則其值可能取決於它所稱的時間和環境。在多個翻譯單元中出現這種初始化表達式會使初始化的執行上下文和時間以及最終的初始值不明確。

一個類範圍的編譯時常量被認爲足夠有價值,可以對某些類型的常量靜態成員(然後可以用來初始化枚舉或指定數組維度等)進行例外。使用常量表達式,在不同的翻譯單元中偶然會產生不同的初始值。這個概念在C++ 11中用constexpr成員進行了擴展。

如果數據成員是具體的類,爲什麼他們宣佈 在全局命名空間範圍,而不是某些範圍與他們 類?

聲明在類範圍內。非定義聲明實際上是在類定義中,並且定義顯示在名稱空間範圍內,就像類成員的任何其他類外定義一樣。成員名稱由類名限定,所以它明確表示爲類的成員,並且初始化表達式實際上被認爲是在該類的範圍內(至少在C++ 11中;我沒有C + +98/03標準在這裏可用)。

+0

「翻譯單元」的含義是「class.h」+「class.cpp」? – user997112 2013-03-01 22:05:44

+0

「翻譯單元」是編譯器編譯的一個單元。通常這是一個單獨的「x.cpp」文件。頭文件通過'#include'指令(遞歸地)包含在翻譯單元中。所以「class.h」的內容是包含文件(直接或間接)的每個翻譯單元的一部分。 「class.cpp」的內容僅在一個翻譯單元(通常)中出現。 – JoergB 2013-03-01 22:11:11

+1

@user:N3485 2.1 [lex.seperate]/1:本標準中的程序文​​本保存在稱爲源文件的單元中。源文件 連同所有頭文件(17.6.1.2)和包含源文件(16.2)的預處理指令 #include,少於任何有條件包含(16.1)預處理指令跳過的源代碼行,被稱爲 翻譯單位。 [注意:一個C++程序不需要全部同時翻譯。 - 結束] – 2013-03-01 22:11:25

1

你必須反過來看看它。基本上,靜態數據成員必須在類定義之外的源文件中定義和初始化。 static const int有個例外,因爲它避免了定義成員數組大小的各種醜陋的變通方法。

相關問題