2012-09-08 65 views
0

我是一個新手程序員,仍然在努力學習C++和OOP設計基礎知識。我一直致力於教自己的項目是一個C++遊戲,它具有多個類,文件,狀態等。但是,我一直在陷入文件組織的困境,其範圍從簡單地掙扎於創建對象的位置到編譯 - 打破鏈接器錯誤。什麼導致這些鏈接器錯誤? (Visual C++ LNK2005)

下面是我已經得到了一些錯誤的例子:

1>SMGA.obj : error LNK2005: "class Engine smgaEngine" ([email protected]@[email protected]@A) already defined in Engine.obj 
1>SplashScreenState.obj : error LNK2005: "class Engine smgaEngine" ([email protected]@[email protected]@A) already defined in Engine.obj 
1>StateManager.obj : error LNK2005: "class StateManager gameStateManager" ([email protected]@[email protected]@A) already defined in Engine.obj 
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library 

我在網上看了看四周,我已經看到了很多類似的〜〜涉及不良的問題包括警衛或包含.cpp文件而不是.h文件。但是我的代碼中沒有這樣做,所以我不知所措。

現在,我猜測錯誤告訴我,我試圖創建引擎類(和StateManager類的gameStateManager對象)的smgaEngine對象兩次,但我不知道爲什麼。 ..

關於這兩個對象(smgaEngine和gameStateManager)突出的是我在類聲明之後立即在他們對應的類的.h文件中聲明它們。這可能是問題嗎? - 他們仍然在包括守衛之內,我不太確定把它們放在我的代碼中的其他位置......這種草率的編碼是鏈接器錯誤的原因嗎?

這裏的犯罪嫌疑人的一個類...

#ifndef ENGINE_H 
#define ENGINE_H 

#include <SDL.h> 
#include "Timer.h" 

class Engine 
{ 
private: 
    static const int screenWidth = 480; 
    static const int screenHeight = 270; 
    static const int screenBPP = 24; 

    bool running; 
    SDL_Surface *mainScreen; 
    SDL_Event eventHolder; 
    Timer fpsTimer; 

public: 
    Engine(); 
    ~Engine(); 

    void init(); 
    void handleEvents(); 
    void handleLogic(); 
    void handleRender(); 
    void cleanUp(); 

    SDL_Event *getEvent(); 

    SDL_Surface *getMainScreen(); 

    bool isRunning(); 
    void setRunning(bool tempRunning); 
} smgaEngine; 

#endif 

而這裏的另一個:

#ifndef STATEMANAGER_H 
#define STATEMANAGER_H 

#include "SplashScreenState.h" 
#include <vector> 

class GameState; 

class StateManager 
{ 
private: 
    std::vector<GameState*> stateStack; 

    SplashScreenState *splashState; 

public: 
    StateManager(); 
    ~StateManager(); 

    void init(); 

    void changeState(GameState *tempNextState); 
    void addState(GameState *tempNextState); 
    void removeState(); 

    //returns the back() element of the stateStack vector.. 
    GameState* getTopState(); 

    void handleEvents(); 
    void handleLogic(); 
    void handleRender(); 
} gameStateManager; 

#endif 

我已經盡我所能去學習C++和OOP,但我真的很掙扎。似乎每次我嘗試使用封裝類來製作乾淨的代碼時,我最終都會產生混亂。我試圖阻止高度的類耦合,但我經常會遇到鏈接器錯誤或缺乏類之間的通信能力......是否在引起這些錯誤的頭文件中創建類實例對象或者是別的什麼?如果這是我的鏈接器錯誤的原因,那麼我應該在哪裏創建這些對象?

回答

6

您已在頭文件中定義了兩個全局變量smgaEnginegameStateManager,並且您已將這些頭文件包含在兩個(或更多)源文件中。所以你會得到多個定義錯誤。包含守護程序不會停止在不同源文件中包含兩次頭文件(它們怎麼可能?)它們會停止在源文件中包含兩次相同中的頭文件。

你很接近正確的答案(至少你對問題有很好的理解)。正確的做法是這樣的

// header file Engine.h 
class Engine 
{ 
}; 

extern Engine smgaEngine; 

// in one source file (say Engine.cpp) 
Engine smgaEngine; 

你現在有什麼是聲明在頭文件(extern使得它的聲明),但在源文件中定義。您可以根據自己的喜好使用盡可能多的聲明(只要它們一致),但只能有一個定義。因此,對於全局變量,在頭文件中放置聲明並將定義放在其中一個源文件中。

+0

啊哈! John非常感謝你提供了清晰而詳細的答案。無論如何,我應該避免使用全局變量! ^^再次感謝! – MrKatSwordfish

+3

很高興提供幫助。 「無論如何我應該避免使用全局變量!」。那麼這就是設計問題,你會在這樣的問題上得到一百萬種不同的意見,而且它們都不會是確定性的。對於面向對象和設計問題,我會建議保持簡單(至少在你學習的時候),並遵循本能地適合你的方式。如果全局變量似乎適合您的需求,並且您沒有看到缺點,那就和他們一起去吧。如果後來你發現全局變量導致問題,那麼至少你會對這些問題有更好的理解。 – john

+0

全面的真棒建議,+1 :) –