2014-01-11 189 views
1

可能重複:linkC++靜態結構類型成員的初始化

大家好,

還有,我不理解靜態成員變量一個奇怪的事情。如果靜態變量的「定義」(我不確定它是否是正確的單詞)在類的頭文件中,編譯器會給出鏈接錯誤,但是如果它們在cpp文件中,則一切正常。

我有一個像如下一類(未粘貼整個事情):

UserInterface.h

class UserInterface 
{ 
public: 
    UserInterface(void); 
    ~UserInterface(void); 

    // Some method declarations here 
private: 
    // Some more methods declarations here 
    // VARIABLES 
    static bool        m_undoRequested; 
    static ChessViewConstants::MENU_STATE  m_displayState; 
    static ChessModelConstants::PieceMovement m_pieceMovement; 
}; 
// THESE DO NOT WORK (linking errors) 
//bool UserInterface::m_undoRequested = false; 
//ChessViewConstants::MENU_STATE UserInterface::m_displayState = ChessViewConstants::MAIN_MENU; 
//ChessModelConstants::PieceMovement UserInterface::m_pieceMovement(1, 1, 1, 1); 

UserInterface.cpp

#include "UserInterface.h" 

// These do work. 
bool UserInterface::m_undoRequested = false; 
ChessViewConstants::MENU_STATE UserInterface::m_displayState = ChessViewConstants::MAIN_MENU; 
ChessModelConstants::PieceMovement UserInterface::m_pieceMovement(1, 1, 1, 1); 

// Implementation.... 

ChessConstants .h

namespace ChessModelConstats{ 
    // Some stuff here... 

    struct PieceMovement { 

    // A simple Constructor 
    PieceMovement(int originRow = -1, int originCol = -1, 
        int targetRow = -1, int targetCol = -1) 
    : m_originRow(originRow), m_originCol(originCol), 
     m_targetRow(targetRow), m_targetCol(targetCol) 
    { 
    } 

     // Members 
     int m_originRow; 
     int m_originCol; 
     int m_targetRow; 
     int m_targetCol; 
    }; 

// More stuff here.... 
} 

那麼爲什麼靜態變量必須在cpp文件內實現呢?爲什麼我不能追加到頭文件的末尾?

第二個問題:我怎麼能初始化結構變量(m_pieceMovement)像如下:

m_pieceMovement.m_originCol = -1; 
m_pieceMovement.m_originRow = -1; 
m_pieceMovement.m_targetCol = -1; 
m_pieceMovement.m_targetRow = -1; 

看來我在這裏缺少一個基本的信息,不要羞於在一些新手扔這裏的技巧和那裏:)提前

感謝,

約翰·約翰

編輯:這是鏈接錯誤:

1> MasterController.obj:錯誤LNK2005: 「私人:靜態布爾的UserInterface :: m_undoRequested」(?m_undoRequested @的UserInterface @@ 0_NA)在Execution.obj已經定義 1> MasterController.obj:錯誤LNK2005: 「Private:static enum ChessViewConstants :: MENU_STATE UserInterface :: m_displayState」(?m_displayState @ UserInterface @@ 0W4MENU_STATE @ ChessViewConstants @@ A)已經在Execution.obj中定義了 1> MasterController.obj:error LNK2005:「private:static struct ChessModelConstants :: PieceMovement UserInterface :: m_pieceMovement「(?m_pieceMovement @ UserInterface @@ 0UPieceMovement @ ChessModelConstants @@ A)已在Execution.obj中定義 1> UserInterface.obj:error LNK2005:」private:static bool UserInterface :: m_undoRequested「(? m_undoRequested @ UserInterf ace @@ 0_NA)已在Execution.obj中定義 1> UserInterface.obj:錯誤LNK2005:「private:static enum ChessViewConstants :: MENU_STATE UserInterface :: m_displayState」?m_displayState @ UserInterface @@ 0W4MENU_STATE @ ChessViewConstants @@ A)已定義in Execution.obj 1> UserInterface.obj:error LNK2005:已在Execution.obj中定義的「private:static struct ChessModelConstants :: PieceMovement UserInterface :: m_pieceMovement」(?m_pieceMovement @ UserInterface @@ 0UPieceMovement @ ChessModelConstants @@ A) 1 > d:\ C++ \ CheatersChess \調試\ CheatersChess.exe:致命錯誤LNK1169:一個或一個以上乘法定義的符號發現

+0

第二個問題完全不清楚。該結構有一個默認的構造函數,而且這些數據成員是公共的,所以它們的初始化有什麼問題? –

+0

如果你有兩個問題,也許你應該問兩個不同的問題。 –

+0

好吧,有些時候我想聲明靜態對象類型成員。我想用object-> initialize()或類似的東西來初始化它。當然,我只想初始化它一次。那我該怎麼做?我不能在一個構造函數中做,唯一的選擇似乎是做一個'#define ObjectInitialized 1'類的東西,我想避免。 –

回答

1

C++標準包括規則稱爲一定義規則。部分是3。2/3:

每個程序都應該包含每個非內聯函數或該程序中odr使用的變量的一個定義; [...]

當你的問題的靜態成員在頭文件中定義的,它的定義將包含在由包括該頭.cpp文件編譯的每一個obj文件。由於許多文件可能包含該標題,因此會得到多個定義,這違反了該規則。 (請注意,對於這種違規行爲,無論所有這些定義是否相同都沒有關係。)

而將定義放入.cpp文件時,該定義僅包含在從此編譯的.obj文件中一個.cpp文件,在鏈接程序時不會導致重複的定義。

關於第二個問題:您需要定義一個構造函數,它將成員的期望值作爲參數。事實上你已經做到了。您可以使用它來定義靜態成員(在.cpp文件中):

ChessModelConstants::PieceMovement UserInterface::m_pieceMovement(-1,-1,-1,-1); 
+0

那麼#ifndef守衛是多重包裹。並且只有一個包含「UserInterface」類的類。我想我需要關於鏈接過程的進一步信息(我不期待你這樣)。感謝澄清。 –

+0

當多個.cpp文件包含相同的頭文件時,include guard不起作用,並且這些.cpp文件中的每一個都單獨編譯*。包含守護程序僅在一個編譯過程中提供幫助,而不是用於多個單獨的編譯過程。即,包含警衛只能在一個翻譯單元中生效。從錯誤消息看來,至少'MasterController.cpp'和'Execution.cpp'包含'UserInterface.h',並且分別編譯。 – jogojapan

+0

那麼''MasterController.h'包含'UserInterface.h'和'Execution.cpp'包含'MasterController.h'因此....我想你是對的。由於沒有人會包含cpp文件,我認爲可以安全地假設在cpp文件中聲明瞭靜態變量。但是,我將如何使用僅頭文件(僅限類定義和一些簡單的方法實現)來做到這一點?有沒有辦法只用頭文件來做到這一點? –