2012-03-29 138 views
0

下面我怎樣才能使程序使用MainMenuScreendraw方法代替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完全是虛擬的,所以請給出其他建議。

回答

5

我該如何讓程序使用 MainMenuScreen而不是GameScreen中的繪圖方法?

你不能,除非你把它的指針或引用,其實際類型爲MainMenuScreen

list<GameScreen> screens; 

聲明瞭一個list對象,而不是指針或引用。如果您將MainMenuScreen對象添加到它,它們將丟失類型信息,因爲對象分割並且多態性不起作用。您需要:

list<GameScreen*> screens; 

,或者更好的:

list<shared_ptr<GameScreen> > screens; 
+0

如何更改我的for循環來實現這一目標? (假設目前所有的列表都是一個MainMenuScreen) – Ben 2012-03-29 22:26:22

+0

@你不能僅僅通過修改for循環,你需要改變'screens'的定義。 – 2012-03-29 22:29:05

+0

謝謝,我不知道。所以如果我改變你的建議,我將如何改變我的for循環?如果我還只是添加指針就足夠了嗎? – Ben 2012-03-29 22:33:10

2

你不想做draw虛擬的,但你想讓它(或保持)虛擬。爲了解決這個問題,你想讓screens列出指針(或者某些類型的智能指針)到GameScreen,而不是GameScreen對象的列表。

因爲它是現在,當你(嘗試)插入您的MainMenuScreen對象到列表中,它被「切」實際上成爲一個GameScreen對象 - 因此,當你走你的列表,你散步的實物類型全部爲GameScreen;希望能夠得到MainMenuScreen在這一點上的行爲是徒勞的。

隨着指針列表,一個MainMenuScreen將保持完全一樣,所以當你調用你的虛函數時,你會得到實際類型的行爲。

+0

它已經是虛擬的,但這並不能解決問題。 – Ben 2012-03-29 22:27:55

+0

@本:是的 - 見編輯答案。 – 2012-03-29 22:30:37

+0

謝謝,這個答案有助於我理解爲什麼它不能工作。我正在嘗試將列表更改爲指針列表。 – Ben 2012-03-29 22:51:38

1

你已經成爲object slicing的受害者。列表中的對象只是您插入其中的對象的副本,並且在創建每個副本後,它將被降級爲包含的類型。

解決方法是在列表中插入指針(最好是智能指針,如shared_ptr)。