2014-01-11 8 views
1

инициализация Возможные дубликат: linkC++ Статические Struct Тип члены

Привет всем,

Там странная вещь, которую я не понимаю, о статических переменных-членов. Если «определение» (я не уверен, что это правильное слово для него) для статических переменных находится в заголовочном файле класса, компилятор дает ссылки на ошибки, однако, если они находятся в файле 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; 

Кажется, я пропускаю основную информацию здесь, не стесняйтесь, чтобы бросить в некоторых новичков советы здесь и там :)

заранее спасибо,

John John

EDIT: Вот связывающие ошибки:

1> MasterController.obj: ошибка LNK2005: "частный: статический BOOL :: m_undoRequested пользовательского интерфейс" (? M_undoRequested @ @@ 0_NA пользовательский интерфейс) уже определены в Execution.obj -> MasterController.obj: ошибка LNK2005: "private: static enum ChessViewConstants :: MENU_STATE UserInterface :: m_displayState" (? m_displayState @ UserInterface @@ 0W4MENU_STATE @ ChessViewConstants @@ A), уже определенный в Execution.obj 1> MasterController.obj: ошибка LNK2005: "private: static struct ChessModelConstants :: PieceMovement UserInterface :: m_pieceMovement "(? M_pieceMovement @ UserInterface @@ 0UPieceMovement @ ChessModelConstants @@ A), уже определенный в Execution.obj 1> UserInterface.obj: ошибка 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) уже определено в Execution.obj 1> UserInterface.obj: ошибка LNK2005: "private: static struct ChessModelConstants :: PieceMovement UserInterface :: m_pieceMovement" (? m_pieceMovement @ UserInterface @@ 0UPieceMovement @ ChessModelConstants @@ A), уже определенный в Execution.obj 1 > D: \ C++ \ CheatersChess \ Debug \ CheatersChess.exe: фатальная ошибка LNK1169: один или несколько умножить определенные символы найдены

+0

Ваш второй вопрос совершенно неясно. Структура имеет конструктор по умолчанию, кроме того, эти члены данных являются общедоступными, так что проблема с их инициализацией ?! –

+0

Если у вас есть два вопроса, возможно, вам следует задать два отдельных вопроса. –

+0

Ну, есть случаи, когда я хочу объявить статический член типа объекта. Я хотел бы инициализировать его с помощью object-> initialize() или что-то в этом роде. Конечно, я хотел бы инициализировать его только один раз. Тогда как мне это сделать? Я не могу сделать это в конструкторе, единственный вариант, похоже, делает объект #define ObjectInitialized 1, который я бы хотел избежать. –

ответ

1

Стандарт C++ включает в себя правило называется правилом на один чёткости. Часть из них - 3.2/3:

Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или переменной, которая используется в этой программе как odr; [...]

Когда статический член вашего вопроса определен в файле заголовка, его определение будет включено в каждый .obj-файл, который скомпилирован из файла .cpp, который включает этот заголовок. Поскольку многие файлы могут включать этот заголовок, вы получаете несколько определений, что является нарушением этого правила. (Обратите внимание, что для этого нарушения не имеет значения, идентичны ли все эти определения.)

Принимая во внимание, что если вы поместите определение в файл .cpp, определение включено только в файл .obj, который скомпилирован из этого один .cpp-файл, не вызывая повторяющихся определений при связывании программы.

Что касается второго вопроса: вам нужно определить конструктор, который принимает требуемые значения для членов в качестве аргументов. Вы уже это сделали. Вы можете использовать это для определения статического члена (в .cpp-файле):

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

Ну, защитник #ifndef предназначен для нескольких включений. И есть только один класс, который включает класс «UserInterface». Я думаю, мне нужна дополнительная информация о процессе связывания (я не ожидаю этого от вас). Спасибо за разъяснения. –

+0

Включенный защитник не помогает, когда несколько файлов .cpp содержат один и тот же заголовок, и каждый из этих .cpp-файлов скомпилирован * отдельно *. Вспомогательные охранники помогают только в одном процессе компиляции, а не для нескольких отдельных процессов компиляции. I.e., включенные охранники вступают в силу только в одной единице перевода. И из ваших сообщений об ошибке кажется, что по крайней мере 'MasterController.cpp' и' Execution.cpp' включают 'UserInterface.h' и скомпилированы отдельно. – jogojapan

+0

Ну, 'MasterController.h' включает' UserInterface.h' и 'Execution.cpp' включает' MasterController.h', так что ... Я думаю, вы правы. Поскольку никто не будет включать файлы cpp, я думаю, что можно с уверенностью предположить, что статические переменные объявлены в cpp-файлах. Но как мне сделать это с только заголовками (только определения классов и некоторые простые реализации методов)? Есть ли способ сделать это с классом только заголовка? –

Смежные вопросы