1

C++ でゲームを作成していますが、派生クラスに問題があります。私は GameScreen と呼ばれる基本クラスを持っています。これには、ステートメントのない vitrual void draw() 関数があります。また、仮想 void draw() 関数を持つ MenuScreen という派生クラスと、同じく void draw() 関数を持つ TestMenu という MenuScreen からの派生クラスもあります。私のプログラムには、GameScreen イテレータが各 GameScreens draw() 関数を呼び出すための GameScreens のリストがあります。

問題は、TestMenu オブジェクトを GameScreen リストに配置したことです。TestMenu の draw() 関数を呼び出す反復子の代わりに、GameScreen クラスの draw() 関数を呼び出しています。GameScreen の代わりに TestMenu の draw() 関数を呼び出す方法を知っている人はいますか?

関数は次のとおりです。

// Tell each screen to draw itself.
//gsElement is a GameScreen iterator
    //gsScreens is a list of type GameScreen
void Draw()
{
    for (gsElement = gsScreens.begin(); gsElement != gsScreens.end(); gsElement++)
    {
        /*if (gsElement->ssState == Hidden)
            continue;*/

        gsElement->Draw();
    }
}   

ここに私のクラスのコピーがあります:

class GameScreen {
public:
    string strName;
    bool bIsPopup;
    bool bOtherScreenHasFocus;
    ScreenState ssState;
    //ScreenManager smScreenManager;

    GameScreen(string strName){
        this->strName = strName;
    }

    //Determine if the screen should be drawn or not
    bool IsActive(){
        return !bOtherScreenHasFocus && 
            (ssState == Active);
    }

    //------------------------------------
    //Load graphics content for the screen
    //------------------------------------
    virtual void LoadContent(){
    }

    //------------------------------------
    //Unload content for the screen
    //------------------------------------
    virtual void UnloadContent(){
    }

    //-------------------------------------------------------------------------
    //Update changes whether the screen should be updated or not and sets
    //whether the screen should be drawn or not.
    //
    //Input:
    //  bOtherScreenHasFocus - is used set whether the screen should update
    //  bCoveredByOtherScreen - is used to set whether the screen is drawn or not
    //-------------------------------------------------------------------------
    virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
        this->bOtherScreenHasFocus = bOtherScreenHasFocus;

        //if the screen is covered by another than change the screen state to hidden
        //else set the screen state to active
        if(bCoveredByOtherScreen){
            ssState = Hidden;
        }
        else{
            ssState = Active;
        }
    }

    //-----------------------------------------------------------
    //Takes input from the mouse and calls appropriate actions
    //-----------------------------------------------------------
    virtual void HandleInput(){
    }

    //----------------------
    //Draw content on screen
    //----------------------
    virtual void Draw(){
    }

    //--------------------------------------
    //Deletes screen from the screen manager
    //--------------------------------------
    void ExitScreen(){
        //smScreenManager.RemoveScreen(*this);
    }
};

class MenuScreen: public GameScreen{
public:
    vector <BUTTON> vbtnMenuEntries; 

    MenuScreen(string strName):GameScreen(strName){
    }

    virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
        GameScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);

        for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++){
            vbtnMenuEntries[i].IsPressed();
        }
    }

    virtual void Draw(){
        GameScreen::Draw();

        for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++)
            vbtnMenuEntries[i].Draw();
    }

};

class testMenu : public MenuScreen{
public:
    vector<OBJECT> test;
    //OBJECT background3();
//  OBJECT testPic(512, 384, buttonHover.png, 100, 40, 100, 40);
//  BUTTON x(256, 384, buttonNormal.png, buttonHover.png, buttonPressed.png, 100, 40, test());
    bool draw;

    testMenu():MenuScreen("testMenu"){
        OBJECT background3(1, 1, 0, TEXT("background.png"), 1, 1, 1024, 768);
        OBJECT testPic(512, 384,0, TEXT("buttonHover.png"), 1, 1, 100, 40);
        test.push_back(background3);
        test.push_back(testPic);
        //background3.Init(int xLoc, int yLoc, int zLoc, LPCTSTR filePath, int Rows, int Cols, int Width, int Height)
        //test.push_back(background3);
    //  vbtnMenuEntries.push_back(x);
        draw = false;
    }

    void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
        MenuScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);
        //cout << "X" << endl;
        /*if(MouseLButton == true){
            testMenu2 t;
            smManager.AddScreen(t);
        }*/
    }

    void Draw(){
        //background3.Draw();
        test[0].Draw();
        test[1].Draw();
        MenuScreen::Draw();
    ///*if(draw){*/
    //  testPic.Draw();
    //}
}

/*void test(){
    draw = true;
}*/

};
4

4 に答える 4

9

gsScreens が (コードが示すように) ポインターのリストではなくオブジェクトのリストである場合、格納していると思われるものを格納していません。

何が起こっているかというと、TestMenu をリストに入れる代わりに、実際には、コンパイラによって生成されたコピー コンストラクターを使用して新しい MenuScreen を構築し、この MenuScreen をリストに入れています。

C++ はポインターを介してポリモーフィックであるため、ポインターがなければポリモーフィックな動作は得られません。

于 2008-09-17T23:18:40.447 に答える
1

目的のポリモーフィックな動作を取得し、同時に a を使用するには、を格納する代わりに、基本クラスの型へのポインターstd::vector<>をベクターに格納する必要があります。また、ベクトルが範囲外になる前にメモリを解放することを忘れないでください。

例えば:

#include <vector>
#include <algorithm>

struct Base
{
    virtual void Foo() = 0;
    virtual ~Base() { }
};

struct Derived1 : public Base
{
    void Foo() { }
};

struct Derived2 : public Base
{
    void Foo() { }
};

struct delete_ptr
{
    template <typename T>
    void operator()(T& p)
    {
        delete p;
        p = 0;
    }
};

int wmain(int, wchar_t*[])
{
    std::vector<Base*> items;
    items.push_back(new Derived1);
    items.push_back(new Derived2);

    Base& first = items.front();
    first.Foo(); // Will boil down to Derived1::Foo().

    Base& last = items.back();
    last.Foo(); // Will boil down to Derived2::Foo().

    std::for_each(items.begin(), items.end(), delete_ptr())
};
于 2008-09-18T06:57:47.613 に答える
0

Boost (www.boost.org、C++ でコーディングするすべての人に推奨するライブラリ) は、まさにそれを行うコピー不可能な基本クラスを提供します。そのように醜いマクロは必要ありません。

于 2008-09-18T16:51:04.363 に答える
0

カートは完全に正しいですが、もう少し情報を提供したいと思います。

この問題 (ポインターではなく基本クラス オブジェクトを格納すること) は、「スライシング」と呼ばれることがあります。

また、次のマクロを使用する傾向があります。

#define DISALLOW_COPYING(X) \
    private: \
        X(const X &); \
        const X& operator= (const X& x)

次に、これをクラス定義のどこかに置きます。

class Foo {
    // ...
    DISALLOW_COPYING(Foo);
};

別のクラスがオブジェクトをコピーしようとすると、コンパイラ エラーが発生します (メソッドがプライベートに宣言されているため)。クラス自体がオブジェクトをコピーしようとすると、リンカー エラーが発生します (メソッドに実装がないため)。

于 2008-09-18T07:05:11.450 に答える