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;

また、2つの子クラスがあります。そのうちの1つは、この3つの仮想関数をオーバーライドし、2つ目はこの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)" (GAMEPLAY_SCREEN_HideTargetBox@UserInterface@@UAEXXZ)
Error 7 error LNK2001: unresolved external symbol "public: virtual void __thiscall UserInterface::GAMEPLAY_SCREEN_ShowTargetBox(void)" (GAMEPLAY_SCREEN_ShowTargetBox@UserInterface@@UAEXXZ)
Error 6 error LNK2001: unresolved external symbol "public: virtual void __thiscall UserInterface::update(void)" (?update@UserInterface@@UAEXXZ)

誰かがそのエラーを取り除く方法を知っていますか?

4

4 に答える 4

7

これらはコンパイルエラーではなく、リンクエラーです。ソースは正常にコンパイルされましたが、基本クラスの3つの仮想関数の実装を提供していませんでした。

クラス宣言でメンバー関数について言及したときは、関数を宣言するだけでした。関数の名前、パラメータータイプ、および戻りタイプをコンパイラーに指示しました。これはコンパイラを幸せにします。リンカを満たすには、実装を提供するか、関数を抽象としてマークする必要があります。

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;
于 2012-07-12T12:50:06.573 に答える
4

の本体を定義する必要があるためUserInterface::GAMEPLAY_SCREEN_HideTargetBox(これがユーザーとアプリケーションのロジックに問題がない場合は、空の実装である可能性があります)。

この関数の定義を基本クラスに含めたくない場合は、純粋な仮想にします。

virtual void GAMEPLAY_SCREEN_HideTargetBox() = 0;

これにより、基本クラスUserInterfaceが抽象になり(タイプを持つオブジェクトを作成できなくなりますUserInterface)、すべての派生クラス(非抽象にしたい)はこの関数の本体を定義する必要があります。

PSこれらはリンカーエラーであり、コンパイラエラーではありません。

于 2012-07-12T12:48:53.940 に答える
1

本当に速いです、それは「基本」クラスと「派生」クラス(または「サブクラス」)であり、親と子のクラスではありません。

私がC++に取り組んでから10年が経ちましたが、問題はLoginScreenUserInterfaceクラスが仮想メソッドを実装していないことが原因だと思います。仮想メソッドがオーバーライドされない場合、基本クラスの実装が呼び出されます。メソッドの基本クラスの実装がないため。リンクエラーが発生しています。デフォルトの実装なしで仮想基本クラスが必要な場合は、最後にa = 1を追加して、純粋な仮想クラスとして宣言する必要があります。

virtual void update()= 0;

これにより、派生クラスは実装を提供するように強制されます。派生クラスに実装を強制したくない場合は、基本クラスに{}のようなものを提供します。

于 2012-07-12T13:03:56.930 に答える
1

コンパイラは、ソースを調べても、親クラスを単独でインスタンス化する人がいないことを証明できません。したがって、親の仮想メソッドテーブルを作成し、そのテーブルを初期化するために、リンカは親の関数のアドレスを探します。

これを回避するには、定義に= 0を追加して、親関数を純粋な仮想として宣言する必要があります。このようにして、コンパイラはそれ自体で親クラスのインスタンス化を禁止し、VMTにNULLを入れ、リンカは何も探す必要がありません。

于 2012-07-12T13:07:53.870 に答える