我的問題:爲了確保它的地址是可用的,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;
}
我的問題:爲了確保它的地址是可用的,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;
}
其他的答案已經給出瞭如何解決它 - 我會去多進爲什麼。
當你這樣做:
#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
不一個完整的類型。
其中一個是類內是可變k
的聲明。你需要定義它恰好在一個翻譯單位爲了正確地鏈接你的程序。因此,該聲明是必需的。
s /編譯單元/翻譯單元/和我會+1;) – 2010-09-09 06:42:32
「定義」類實際上只提供A::k
的「聲明」。是的,我知道它很混亂,但我的想法是允許類定義在.h
(包含多個.cpp
來源)中,而不會產生歧義:這些來源中的一個且只有一個必須提供實際的定義以匹配A::k
的聲明(後者是類別A
的定義的一部分)。
類內部是聲明。所以如果我不定義* C++仍然允許我訪問它?顯然cout << A :: k工作正常。 – Fanatic23 2010-09-09 05:03:16
@Arpan:是的,但該代碼根據標準無效。因此你的編譯器可以做任何喜歡的事情。 – 2010-09-09 05:15:33
@Billy ONeal:3美元。2/2-「如果其名稱出現在可能評估的表達式中,則使用對象或非重載函數。」當A :: k用作'<<'操作符的操作數時,它將被評估。一個對象只有在存在和被定義的情況下才能被評估。所以,如果A :: K沒有定義,它真的是一個未定義的行爲,或者它是一個需要診斷的錯誤(在這種情況下在鏈接階段)。 – Chubsdad 2010-09-09 06:33:22
一個靜態變量可以被認爲是由該類的所有對象共享的數據,因此應該只創建該變量的一個副本。有了這個說法,誰應該爲這個成員分配內存的責任呢?顯然,它不能成爲對象的責任,因爲可能有多個對象會引發另一個挑戰,即哪個對象應該爲這個成員分配內存。
所以通常compliler預計淘汰類,這個成員的明確定義,因此該行:
const float A::k;
這確保了靜態成員變量是在類的所有對象的訪問。此變量的內存分配在全局可訪問的內存中。
這聽起來像你想知道爲什麼變量需要定義,即使你沒有訪問它。
要打印它的地址,它需要一個地址。有一個地址,它必須存在。爲了存在,它需要有一個定義,並且鏈接器需要爲它在全局變量空間中分配一個位置。所以,真的沒有一箇中間立場。
「引擎蓋下」,該定義告訴鏈接器全局的初始化器是什麼。 (在這種情況下,初始化程序位於class
塊中,但這不是標準的,官方的方式是編寫const float A::k = 7.7;
)。不知道它不能生成可執行文件。
而且,除非編譯器執行不可能詳細的分析,它不能真正告訴operator <<
不以某種方式說指針傳遞給其他一些功能或OS服務,將訪問k
值。
如果你可以這樣定義static const float k = 7.7;
如你所願,你將在多重定義結束(因爲靜態成員將只有一次定義),無論你是包括它。
爲了避免定義在cpp
文件中單獨存在。
從C++標準文檔秒9.4.1,
靜態數據成員是不是類的子對象的一部分。有只有一個副本靜態數據成員共享 所有對象的類。
另外9.4.2指出,
在其類定義靜態數據成員的聲明是不是定義,並且可以是一個不完整的類型 比CV-合格空隙其他的。對於靜態數據成員的定義應在的命名空間範圍中出現,其中包含 成員的類定義。
希望它可以幫助..
可能的重複:http://stackoverflow.com/questions/3575580/rationale-behind-static-const-member-initialization-syntax – sje397 2010-09-09 04:52:45
這不是重複的。我想了解爲什麼cout << A :: k有效,但不是cout << &A::k; – Fanatic23 2010-09-09 05:04:58
該代碼不應該編譯。只有靜態const **集成**成員可以在類中以這種方式進行初始化。 – 2010-09-09 05:14:46