2011-08-06 127 views
7

我有一個叫頭filepaths.h它定義了一些靜態變量:爲什麼靜態變量需要在C++中聲明兩次

#ifndef FILEPATHS_H 
#define FILEPATHS_H 

class FilePaths { 

public: 

    static QString dataFolder(); 
    static QString profileFolder(); 

private: 

    static QString dataFolder_; 
    static QString profileFolder_; 

}; 

} 
#endif // FILEPATHS_H 

而且我有一個相關的filepaths.cpp這一開始是這樣的:

#include "FilePaths.h" 

QString FilePaths::dataFolder() { 
    return dataFolder_; 
} 

QString FilePaths::profileFolder() { 
    return profileFolder_; 
} 

但是沒有工作 - 我對所有的靜態變量得到了一個「未解決的符號錯誤」連接錯誤。所以我以這種方式添加這些變量到C++文件:

#include "FilePaths.h" 

QString FilePaths::dataFolder_ = ""; 
QString FilePaths::profileFolder_ = ""; 

QString FilePaths::dataFolder() { 
    return dataFolder_; 
} 

QString FilePaths::profileFolder() { 
    return profileFolder_; 
} 

而這個工作,但是我不明白爲什麼。

爲什麼這些靜態變量需要定義兩次?或者,也許我沒有定義他們,但初始化他們?但仍然爲什麼需要這樣做?還是應該以不同的方式寫我的課程?

回答

8

一個是定義,另一個是聲明。不同之處在於聲明可以多次出現,對於不在類中的變量,可能永遠不會出現,而定義只能出現一次。

需要單獨聲明和定義的原因是古老的歷史,它基本上不必是那種方式,但它是這樣的,以便C++與C兼容,C被設計爲在20世紀70年代被編輯。

+3

我不認爲這是古老的。聲明聲稱「存在某個名爲X的變量/類/函數」,而定義說「X駐留在這裏,編譯器請爲它分配存儲空間」。分離聲明和定義的能力是允許多種翻譯單元採用靜態類型的語言,而編譯器不需要過度「聰明」並猜測自己的意圖。 – vsekhar

+0

這並不是很陳舊,因爲這兩個標準(甚至現在,C99/C++ 11)在實際的鏈接器進程上都非常模糊,並且某個cpp文件中的定義將導致生成的目標文件中有一個定義,如果這並非如此,鏈接器在將所有代碼鏈接在一起時不會找到唯一的引用。 – rubenvb

+0

vsekhar,@rubenvb:我會注意到,對於模板代碼,我們獲得了函數和靜態屬性的多個定義(在對象文件中),但鏈接器管理它們是正確的。 –

2

http://weblogs.asp.net/whaggard/archive/2004/11/05/252685.aspx

你需要聲明它的類之外,因爲否則編譯器不知道哪個翻譯單元(因此目標文件)的成員應該去。

因爲,就像DeadMG說的那樣,你可以多次聲明一個變量,但只定義它一次。我認爲它就像函數原型一樣:你可以擁有儘可能多的函數原型,但是隻有一個可以與一個物體一起去實際定義函數。

0

你不要聲明它們兩次,聲明發生在類頭和定義 - 變量實際存在並將分配一些內存的位置 - 位於.cpp部分。

但是,與常見實例變量的區別在於,對於您創建的任何實例,靜態部分僅對每個類有一次。

0

這是因爲,當你聲明一個類的時候,你就是爲這個類的特定實例聲明一個結構,但是在類中有靜態變量的情況下,它們是可以在任何對象之前初始化的結構的類被創建。 SEE當我們在內存中聲明一個類時沒有保留空間,但是當我們聲明類的對象時,空間是保留的。類的成員可以被初始化,如 int a = 2;但是這可以像'static int a = 2;'那樣完成有可能 在類聲明的預留空間爲他們有第二個聲明,&必須讓它知道它

相關問題