2017-08-07 93 views
2

我想用一個虛函數擴展一個抽象基類,並將函數名稱保持爲虛擬,但在「可能」重寫的子函數之前和之後運行代碼。你可以重寫同一個類中的純虛函數嗎?

下面是一個例子:

我對事物的基類(接口),可以得出:

class IDraw { 
    public: 
     virtual void do_draw(Screen *scr) = 0; 
}; 

我想保持這種接口在子類中,並能夠覆蓋它, 例如我有一個遊戲,其中清潔所述屏幕的一類,繪製的東西,並比翻轉顯示緩衝器:

class Game : public IDraw { 
    public: 
     // Keep the interface 
     // This can be overridden by sub classes 
     virtual void do_draw(Screen *scr) = 0; // (1) 
    private: 
     // But override the base class so if s.b. calls 
     // do_draw from a IDraw pointer it executes this! 
     void IDraw::do_draw(Screen *scr) override; // (2) 
}; 

// Implementation of (2) 
void Game::IDraw::do_draw(Screen *scr) { 
    // Do stuff before like clear the screen 
    scr->clear(); 
    // Call the method supplied by childs 
    this->do_draw(scr); // (1) 
    // Present the drawing 
    scr->present(); 
} 

由於我有代碼之前和之後由孩子提供的功能我不能簡單地重寫使其保持虛擬,因爲孩子必須決定是否在之前或之後調用Game :: do_draw()//(2)。

我知道我可以簡單地用不同的名稱調用函數(2),但是因爲我需要很多類來做這種事情,所以它會以相同概念的大量名字結尾。

有沒有辦法在C++ 11中做這種事情?

+1

不可以。您不能用不同的名稱覆蓋功能。 – SergeyA

回答

2

我想保持在子類中的接口,並能夠覆蓋它,

這將是已經的情況下自動的,因爲你繼承了它在public訪問級別。

比如我有一個遊戲,其中清潔屏幕類,畫的東西,比翻轉顯示緩衝區...
... 有沒有辦法做這樣的事情用C++ 11?

完全獨立於任何C++ 11個特殊性,只寫爲抽象函數聲明一個實現中,並添加額外的間接層(又名Template Method Pattern):

class Game : public IDraw { 
public: 
    // Keep the interface 
    // This can be overridden by sub classes 
    void do_draw(Screen *scr) override { 
     OnPreDraw(scr); 
     OnDraw(scr); 
     OnPostDraw(scr); 
    } 
protected: 
    virtual void OnPreDraw(Screen *scr) { 
     // Default implementation 
     scr->clear(); 
    } 
    virtual void OnDraw(Screen *scr) = 0; // << Class is still abstract 
    virtual void OnPostDraw(Screen *scr) { 
     // Default implementation 
     scr->present(); 
    } 
}; 

這將允許在更細粒度的操作序列中注入Game的任何實現,但保留基類實現的默認行爲。
此外,基類仍然是抽象的,並且有效地強制任何派生類實現OnDraw(),這與do_draw()實際上是相同的。

但是因爲我需要很多類來做這種東西,它將以相同概念的大量名稱結束。

號就你概念只是涉及到操作

OnPreDraw(scr); 
OnDraw(scr); 
OnPostDraw(scr); 
在該序列

,不會對整個類繼承層次今後不再發生任何改變。


要將延伸:

也可以做到這一點與Mixin pattern

template<typename Derived> 
class AbstractIDrawImpl : public IDraw { 
    void do_draw(Screen *scr) override { 
     static_cast<Derived*>(this)->OnPreDraw(scr); 
     static_cast<Derived*>(this)->OnDraw(scr); 
     static_cast<Derived*>(this)->OnPostDraw(scr); 
    } 

    // Expects public implementations 
    void OnPreDraw(Screen *scr) { 
     // Default implementation 
     scr->clear(); 
    } 
    // Just no default implementation for 
    // void OnDraw(Screen *scr) << Class is still abstract 
    void OnPostDraw(Screen *scr) { 
     // Default implementation 
     scr->present(); 
    } 
}; 

上述混入例如可以綁定到的IDraw任何實現,它提供public功能爲OnPreDraw(),OnDraw()OnPostDraw()

class MyGame : public AbstractIDrawImpl<MyGame> { 
public: 
    // IDraw interface implementation 
    void OnPreDraw(Screen *scr) { 
     // Call base class implementation 
     AbstractIDrawImpl<MyGame>::OnPreDraw(scr); 
     // E.g fill my background here 
    } 
    void OnDraw(Screen *scr) { 
     // For each game entity call 
     // IDraw::do_draw(scr); 
     for(auto drawableEntity : drawableEntities_) { 
      drawableEntity->do_draw(scr); 
     } 
    } 
    // Skip implementation of OnPostDraw() 
private: 
    std::vector<std::shared_ptr<IDraw>> drawableEntities_; 
}; 

1)
即圖案是公用克塞Andrescou的Policy based design paradigm描述和Microsoft's ATL大量使用。

+1

這就是我最終使用的,但我想知道是否有一種方法可以避免許多函數名稱爲相同的事情,因爲它不會是相同的擴展IDraw或遊戲,因此,如果我決定更改爲遊戲父項我必須照顧改變覆蓋名稱相應 – DarioDF

+0

@DarioDF那麼,這是做AFAIK的最佳模式。另一種選擇可能是進入CRTP和靜態多態/ mixins的方向。我懷疑這是值得的。這種模式很好地滿足了你的需求,並且爲派生類增加了另一個間接級別。 – user0042

+0

@DarioDF我已經擴展了我的答案。 – user0042

相關問題