2012-07-12 72 views
4

我有這樣的父類:爲什麼在父類中聲明虛函數時會出現無法解析的外部錯誤?

enum UI_STATE 
{ 
    UI_STATE_SPLASH_SCREEN, 
    UI_STATE_LOGIN_SCREEN, 
    UI_STATE_CHARACTER_CREATION_SCREEN, 
    UI_STATE_CHARACTER_CHOOSE_SCREEN, 
    UI_STATE_LOADING_SCREEN, 
    UI_STATE_GAMEPLAY, 
    UI_STATE_EXIT_REQUESTED, 
    UI_STATE_UNKNOWN 
}; 

[event_source(native)] 
class UserInterface 
{ 
protected: 
    MyGUI::Gui *mGUI; 

public: 
    static UserInterface *Instance; 
    UI_STATE UI_CURRENT_STATE; 

public: 
    UserInterface() 
    { 
     MyGUI::OgrePlatform* mPlatform = new MyGUI::OgrePlatform(); 
     mPlatform->initialise(BaseObjects::mWindow, BaseObjects::mSceneMgr); 
     mGUI = new MyGUI::Gui(); 
     mGUI->initialise(); 

     UI_CURRENT_STATE = UI_STATE_UNKNOWN; 
    } 

    ~UserInterface() 
    { 
     mGUI->destroyAllChildWidget(); 
     mGUI->shutdown(); 

     delete mGUI; 
     mGUI = NULL; 

     delete Instance; 
     Instance = NULL; 
    } 

    virtual void update(); 
    virtual void GAMEPLAY_SCREEN_ShowTargetBox(); 
    virtual void GAMEPLAY_SCREEN_HideTargetBox(); 

...//some other methods 
} 

UserInterface *UserInterface::Instance = NULL; 

也有兩個子類,其中之一就是覆蓋這3個虛函數和第二什麼都不做這個3種功能。

兒童1:

#ifndef GameplayScreenInterface_h 
#define GameplayScreenInterface_h 

#include "UserInterface.h" 
#include "ControllableCharacterAdv.h" 

class GameplayScreenUserInterface : public UserInterface 
{ 
private: 
... 

public: 
    GameplayScreenUserInterface() 
    { 
... 
    } 

    void GAMEPLAY_SCREEN_ShowTargetBox() 
    { 
     ... 
    } 

    void GAMEPLAY_SCREEN_HideTargetBox() 
    { 
     ... 
    } 

    void update() 
    { 
     UpdateTargetBox(); 
     UpdateCharacterBox(); 
    } 

    void UpdateCharacterBox() 
    { 
... 
    } 

    void UpdateTargetBox() 
    { 
     if (...) 
     { 
      if (...) 
      { 
      ... 
      } 
      else if (...) 
      { 
... 
      } 
      else 
      { 
      ... 
      } 
     } 
     else 
      GAMEPLAY_SCREEN_HideTargetBox(); 
    } 
}; 

#endif GameplayScreenInterface_h 

和2兒童:

#ifndef LoginScreenInterface_h 
#define LoginScreenInterface_h 

#include "UserInterface.h" 
#include "NetworkManager.h" 

class LoginScreenUserInterface : public UserInterface 
{ 
public: 
    LoginScreenUserInterface() 
    { 
... 
    } 
}; 

#endif LoginScreenInterface_h 

和編譯錯誤:(

Error 9 error LNK1120: 3 unresolved externals 
Error 8 error LNK2001: unresolved external symbol "public: virtual void __thiscall UserInterface::GAMEPLAY_SCREEN_HideTargetBox(void)" ([email protected]@@UAEXXZ) 
Error 7 error LNK2001: unresolved external symbol "public: virtual void __thiscall UserInterface::GAMEPLAY_SCREEN_ShowTargetBox(void)" ([email protected]@@UAEXXZ) 
Error 6 error LNK2001: unresolved external symbol "public: virtual void __thiscall UserInterface::update(void)" ([email protected]@@UAEXXZ) 

任何人有任何想法如何擺脫的錯誤?

回答

6

這些不是編譯錯誤,這些都是鏈接錯誤。你的源代碼編譯得很好,但是你沒有提供基類中三個虛函數的實現。

當你在一個類聲明中提到的成員函數,你所做的一切是聲明功能:你告訴編譯器有什麼功能的名稱,什麼是它的參數類型,以及什麼是它的返回類型;這使編譯器感到高興。您仍然需要提供一些實現,或者標記抽象函數,以便滿足鏈接器。

在與UserInterface實施你的CPP文件中添加這些:

void UserInterface::update() { 
    // default implementation 
} 
void UserInterface::GAMEPLAY_SCREEN_ShowTargetBox() { 
    // default implementation 
} 
void UserInterface::GAMEPLAY_SCREEN_HideTargetBox() { 
    // default implementation 
} 

Alternativelt,如果有一些或所有這些虛函數沒有缺省實現,在頭部添加= 0

virtual void update() = 0; 
virtual void GAMEPLAY_SCREEN_ShowTargetBox() = 0; 
virtual void GAMEPLAY_SCREEN_HideTargetBox() = 0; 
+0

謝謝,用void UserInterface :: update(){}幫助我! – Kosmos 2012-07-12 13:08:27

+0

你應該補充說後者不適用於純虛擬析構函數,它們應該總是有一個正文。 – 2014-10-13 23:31:54

4

因爲您需要爲UserInterface::GAMEPLAY_SCREEN_HideTargetBox定義一個正文(如果這對您和您的應用程序的邏輯來說可能是空的,它可能是空的實現)。

如果你不希望有在基類中該函數的定義,使其純虛:

virtual void GAMEPLAY_SCREEN_HideTargetBox() = 0; 

這會讓你的基類UserInterface抽象(你將無法創建對象類型爲UserInterface)以及所有派生類(您希望是非抽象的)必須爲定義此函數的主體。

P.S.這些是鏈接器錯誤,而不是編譯器錯誤。

1

真的很快,它是「基礎」類和「派生」類(或「子類」),而不是父類和子類。

我從事C++工作已有十年了,但我相信問題在於您的LoginScreenUserInterface類沒有實現虛擬方法。如果虛擬方法未被覆蓋,則調用基類實現。由於您沒有方法基類實現。您收到鏈接錯誤。如果你想擁有一個沒有默認實現的虛擬基類,你應該通過在末尾添加一個= 1來聲明它是純虛擬的:

virtual void update()= 0;

這將強制任何派生類提供實現。如果您不想強制派生類提供實現,請在基類中提供類似{}的內容。

+0

「我相信這個問題是因爲你的LoginScreenUserInterface類沒有實現虛擬方法」這應該是真的,如果我聲明這些函數爲純虛擬。現在我明白了,我只需要在基類中爲它們提供實現 – Kosmos 2012-07-12 13:19:22

+0

如果這有助於將我投票:) – user1496786 2012-07-12 14:27:06

+0

好的,但回答包含此部分中的錯誤信息:「我相信問題是因爲您的LoginScreenUserInterface類未實現虛擬方法如果一個虛擬方法沒有被覆蓋,那麼這個基類實現就被調用了。「這隻有當我確實將這些函數聲明爲純虛函數時纔是真實的 – Kosmos 2012-07-12 15:25:34

1

編譯器無法通過查看源代碼來證明沒有人會自行實例化父類。因此,它爲父級創建虛擬方法表,並初始化該表,鏈接程序正在查找父級函數的地址。

爲了避免這種情況,您需要通過將= 0附加到定義來聲明父虛函數爲純虛函數。這樣編譯器將禁止自己實例化父類,將NULL置於VMT中,並且鏈接器沒有任何可查找的內容。

相關問題