2010-09-09 47 views
2

我的問題:爲了確保它的地址是可用的,k下的類外定義究竟在做什麼?需要超出靜態變量的類定義嗎?

#include <iostream> 
using namespace std; 

class A { 
    public: 
    static const float k = 7.7; 
}; 

//const float A::k; --> without this line compiler error 

int main() 
{ 
    cout << &A::k; 
} 
+0

可能的重複:http://stackoverflow.com/questions/3575580/rationale-behind-static-const-member-initialization-syntax – sje397 2010-09-09 04:52:45

+0

這不是重複的。我想了解爲什麼cout << A :: k有效,但不是cout << &A::k; – Fanatic23 2010-09-09 05:04:58

+1

該代碼不應該編譯。只有靜態const **集成**成員可以在類中以這種方式進行初始化。 – 2010-09-09 05:14:46

回答

1

其他的答案已經給出瞭如何解決它 - 我會去多進爲什麼。

當你這樣做:

#include <iostream> 
using namespace std; 

class A { 
    public: 
    static const float k = 7.7; 
}; 

int main() 
{ 
    cout << A::k; 
} 

編譯器可能是在現實中發生這樣的:

#include <iostream> 
using namespace std; 

class A { 
    public: 
    static const float k = 7.7; 
}; 

int main() 
{ 
    cout << 7.7; 
} 

,這意味着會有這個轉換單元和A::f之間沒有聯繫時依賴 - 編譯後的代碼根本沒有引用A::f

但是,當您使用&A::f時,您強制編譯器生成A::f的地址。因此翻譯單元確實A::f有依賴。既然你還沒有定義它,你會得到一個鏈接器錯誤,因爲鏈接器找不到它的地址。對於存在的地址,A::f必須在一個中定義,並且只有一個翻譯單元。要選擇它應該駐留的翻譯單元,您需要在那裏定義它。

你也有你的類上面的代碼無效的問題,但 - 只有靜態常量組成成員可能與你所使用的語法(把K = 7.7類體)來初始化 - float不一個完整的類型。

1

其中一個是類內是可變k聲明。你需要定義它恰好在一個翻譯單位爲了正確地鏈接你的程序。因此,該聲明是必需的。

+0

s /編譯單元/翻譯單元/和我會+1;) – 2010-09-09 06:42:32

2

「定義」類實際上只提供A::k的「聲明」。是的,我知道它很混亂,但我的想法是允許類定義在.h(包含多個.cpp來源)中,而不會產生歧義:這些來源中的一個且只有一個必須提供實際的定義以匹配A::k聲明(後者是類別A定義的一部分)。

+0

類內部是聲明。所以如果我不定義* C++仍然允許我訪問它?顯然cou​​t << A :: k工作正常。 – Fanatic23 2010-09-09 05:03:16

+0

@Arpan:是的,但該代碼根據標準無效。因此你的編譯器可以做任何喜歡的事情。 – 2010-09-09 05:15:33

+0

@Billy ONeal:3美元。2/2-「如果其名稱出現在可能評估的表達式中,則使用對象或非重載函數。」當A :: k用作'<<'操作符的操作數時,它將被評估。一個對象只有在存在和被定義的情況下才能被評估。所以,如果A :: K沒有定義,它真的是一個未定義的行爲,或者它是一個需要診斷的錯誤(在這種情況下在鏈接階段)。 – Chubsdad 2010-09-09 06:33:22

0

一個靜態變量可以被認爲是由該類的所有對象共享的數據,因此應該只創建該變量的一個副本。有了這個說法,誰應該爲這個成員分配內存的責任呢?顯然,它不能成爲對象的責任,因爲可能有多個對象會引發另一個挑戰,即哪個對象應該爲這個成員分配內存。

所以通常compliler預計淘汰類,這個成員的明確定義,因此該行:

const float A::k;

這確保了靜態成員變量是在類的所有對象的訪問。此變量的內存分配在全局可訪問的內存中。

1

這聽起來像你想知道爲什麼變量需要定義,即使你沒有訪問它。

要打印它的地址,它需要一個地址。有一個地址,它必須存在。爲了存在,它需要有一個定義,並且鏈接器需要爲它在全局變量空間中分配一個位置。所以,真的沒有一箇中間立場。

「引擎蓋下」,該定義告訴鏈接器全局的初始化器是什麼。 (在這種情況下,初始化程序位於class塊中,但這不是標準的,官方的方式是編寫const float A::k = 7.7;)。不知道它不能生成可執行文件。

而且,除非編譯器執行不可能詳細的分析,它不能真正告訴operator <<不以某種方式說指針傳遞給其他一些功能或OS服務,訪問k值。

1

如果你可以這樣定義static const float k = 7.7;如你所願,你將在多重定義結束(因爲靜態成員將只有一次定義),無論你是包括它。

爲了避免定義在cpp文件中單獨存在。

從C++標準文檔秒9.4.1,

靜態數據成員是不是類的子對象的一部分。有只有一個副本靜態數據成員共享 所有對象的類。

另外9.4.2指出,

在其類定義靜態數據成員的聲明是不是定義,並且可以是一個不完整的類型 比CV-合格空隙其他的。對於靜態數據成員的定義應在命名空間範圍中出現,其中包含 成員的類定義。

希望它可以幫助..

相關問題