在下文中,如何使程序使用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
)插入到列表中。