2012-07-12 79 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中,并且链接器没有任何可查找的内容。

相关问题