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



在下文中,如何使程序使用MainMenuScreen中的draw方法,而不是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 */
        }
    }
};

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

如何使程序使用来自MainMenuScreen而不是GameScreen中的那个?

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

 list<GameScreen> screens;

声明了对象的list,而不是指针或引用。如果向其中添加MainMenuScreen对象,它们将丢失类型信息,因为对象切片,多态性将不起作用。您需要:

 list<GameScreen*> screens;

或者,更好的是:

 list<shared_ptr<GameScreen> > screens;

您不想使draw虚拟化,但您确实想使它(或保持它)虚拟化。为此,您需要使screens成为指向GameScreen指针的列表(或者可能是某种智能指针),而不是GameScreen对象的列表。

现在,当你(试图)将MainMenuScreen对象插入列表时,它被"切片",实际上变成GameScreen对象——因此,当你遍历列表时,你遍历的是一个实际类型均为GameScreen的对象列表;希望从他们中的任何一个人那里得到CCD_ 15行为是徒劳的。

有了指针列表,MainMenuScreen将保持原样,因此当您调用虚拟函数时,您将获得实际类型的行为。

您已经成为对象切片的牺牲品。列表中的对象只是插入到其中的对象的副本,并且在创建每个副本时,都会降级为包含的类型。

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

最新更新