C ++派生类问题

时间:2008-09-17 23:06:49

标签: c++ inheritance

我正在使用C ++制作游戏,并且我的派生类出现问题。我有一个名为GameScreen的基类,它有一个没有语句的vitrual void draw()函数。我还有一个名为MenuScreen的派生类,它还有一个虚拟的void draw()函数和一个名为TestMenu的MenuScreen派生类,它也有一个void draw()函数。在我的程序中,我有一个GameScreens列表,我有一个GameScreen迭代器通过调用每个GameScreens draw()函数。

问题是我在GameScreen列表中放置了一个TestMenu对象。而不是迭代器调用TestMenu的draw()函数,而是调用GameScreen类的draw()函数。有谁知道如何调用TestMenu的draw()函数而不是GameScreen中的函数。

这是功能:

// 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 个答案:

答案 0 :(得分:9)

如果gsScreens是一个对象列表而不是一个指针列表(如代码所示),那么你就不会存储你认为存储在其中的内容。

发生的事情是 - 您不是将TestMenu放入列表中,而是使用编译器生成的复制构造函数构建一个新的MenuScreen,并将此MenuScreen放入列表中。

C ++通过指针是多态的,所以如果你没有指针就不会有多态行为。

答案 1 :(得分:1)

要获得您所追求的多态行为并同时使用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())
};

答案 2 :(得分:0)

Curt绝对是正确的,但我只是想向它提供更多信息。

这个问题(存储基类对象而不是指针)有时被称为“切片”。

另外,我倾向于使用以下宏:

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

然后你把它放在你的班级定义中的某个地方:

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

如果另一个类试图复制该对象,则会出现编译器错误(因为这些方法被声明为私有)。如果类本身试图复制该对象,则会出现链接器错误(因为这些方法没有实现)。

答案 3 :(得分:0)

Boost(www.boost.org,我建议任何编写C ++的人使用的库)提供了一个不可复制的基类,就是这样做的。你不需要那种丑陋的宏。