在下文中,我如何才能使程序使用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
纯粹虚拟,所以请提出其他建议。
答案 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
)。