2014-01-11 107 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文件中声明了静态变量。但是,我将如何使用仅头文件(仅限类定义和一些简单的方法实现)来做到这一点?有没有办法只用头文件来做到这一点? –