继承/多态 - 子类的调用方法

时间:2012-03-29 22:22:54

标签: c++ inheritance

在下文中,我如何才能使程序使用draw中的MainMenuScreen方法而不是GameScreen中的方法?

class GameScreen {
public:
    virtual void GameScreen::draw() {
        cout << "Drawing the wrong one..." << endl;
    }
};

class MainMenuScreen : public GameScreen {
public:
    void MainMenuScreen::draw() {
        cout << "Drawing the right one..." << endl;
    }
};

class ScreenManager {
public:
    list<GameScreen> screens;

    // assume a MainMenuScreen gets added to the list

    void ScreenManager::draw()
    {
        for ( list<GameScreen>::iterator screen = screens.begin(); 
              screen != screens.end(); screen++ )
        {
            screen->draw(); /* here it uses the draw method from GameScreen, 
                               but I want it to use the draw method from              
                               MainMenuScreen */
        }
    }
};

PS:我不想让GameScreen::draw纯粹虚拟,所以请提出其他建议。

3 个答案:

答案 0 :(得分:5)

  

我怎样才能使程序使用draw方法   MainMenuScreen而不是GameScreen中的那个?

除非您在实际类型为MainMenuScreen的指针或引用上调用它,否则不能。

 list<GameScreen> screens;

声明list个对象,而不是指针或引用。如果向其添加MainMenuScreen个对象,由于对象切片,它们将丢失类型信息,并且多态无效。你需要:

 list<GameScreen*> screens;

或者,更好的是:

 list<shared_ptr<GameScreen> > screens;

答案 1 :(得分:2)

您不希望draw 虚拟,但您确实想要(或保留)虚拟。要使用它,您希望screens列出指针(或某些类型的智能指针)到GameScreen而不是{{1}的列表对象。

就像现在一样,当你(试图)将你的GameScreen对象插入到列表中时,它被“切片”到实际成为一个MainMenuScreen对象 - - 因此,当你走到你的列表时,你正在走一个实际类型都是GameScreen的对象列表;希望在那一点上得到任何人的GameScreen行为是徒劳的。

使用指针列表,MainMenuScreen将保持不变,因此当您调用虚函数时,您将获得实际类型的行为。

答案 2 :(得分:1)

你已成为object slicing的受害者。列表中的对象只是您插入其中的对象的副本,并且在制作每个副本时,它会降级为包含的类型。

解决这个问题的方法是在列表中插入指针(最好是智能指针,如shared_ptr)。