2017-08-07 17 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(); 
    } 
}; 

で上記のミックスインの例では、publicを提供IDrawのいずれかの実装にバインドできるようにしても行うことができます拡張するために


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またはGameを拡張することはできません。私はそれに応じてオーバーライドの名前を変更する世話をする必要があります – DarioDF

+0

@DarioDFそれは、AFAIKを行うための最良のパターンです。別の選択肢は、CRTPと静的多型/混合物の方向に進むことです。私はそれがそれに値するのは疑いがあります。そのパターンはあなたが望むものをうまく実行し、クラスを導出するための間接参照のレベルを追加するだけです。 – user0042

+0

@DarioDF私は私の答えを少し拡張しました。 – user0042

関連する問題