2

Non-virtual Interface idiome (NVI) はかなり自明です:public virtual関数を書くのではなく、次のように実装関数publicを呼び出す関数を記述します。private virtual

class Object{
    virtual void v_load();
public:
    void load(){ v_load(); }
}

これにより、基本クラスの作成者は、事前条件と事後条件をチェックして適用したり、他の関数を適用したりして、派生クラスの作成者がそれらを忘れないようにすることができます。

あなたが派生作成者である場合、基本クラスを自分で書きたいと思うかもしれません - それを呼びましょうPawn- それは の機能を拡張するload()ため、オーバーライドする必要がありますv_load()。しかし今、あなたは問題に直面しています:

をオーバーライドv_load()すると、クラスから派生したい他のクライアントは常にその動作を上書きしPawn::v_load()private関数であるため呼び出すことも、もちろん無限ループにつながるようにPawn::load()定義されているため呼び出すこと{ v_load; }もできませんObject. さらに、そうするように要求すると、その呼び出しを忘れたときにミスが発生する可能性があります。それを有効にしたい場合は、へのアクセスを のように指定する必要v_load()protectedありObjectますObject

v_load()もちろん、新しい関数を呼び出すためにオーバーライドすることもできますv_pawnLoad()。これはクライアントによってオーバーライドされますが、多くのクライアントが間違った関数をオーバーロードする可能性があるため、エラーが発生しやすいようです。

では、前提条件をチェックしたり、他の関数を呼び出したり、(可能であれば) 有効にせずに、クライアントに要求したり、基本実装を呼び出したりする機能を維持しながらPawn、クライアントがオーバーライドできるように設計するにはどうすればよいでしょうか?v_load()ObjectPawnv_load()

4

2 に答える 2

2
  • 「置換」の動作とは対照的に、人々が「拡張」できるようにすることが意図されてloadいる場合は、現在持っているコードを入れて、最後に空v_loadload呼び出しますv_load
  • またはv_load protected、人々に「置き換える」か「拡張する」かを選択させたい場合は、単に作成することもできます。
  • それらが動作を置き換えることを許可したいだけであれば、コードはそのままで問題ありません。

v_loadおまけとして、これら 3 つのバリアントすべてで、デフォルトの動作がない場合は、純粋な仮想にすることで「許可」を「強制」に変更できます。

Pawnオーバーライドを子クラスに限定したい場合は、finalキーワードをv_loadinに追加し、Pawn別の仮想関数を使用して、 の子クラスがPawnその動作をカスタマイズできるようにします。

于 2014-08-21T15:02:24.463 に答える