web-dev-qa-db-ja.com

C ++のプライベート仮想メソッド

C++でプライベートメソッドを仮想化する利点は何ですか?

オープンソースのC++プロジェクトでこれに気付きました。

class HTMLDocument : public Document, public CachedResourceClient {
private:
    virtual bool childAllowed(Node*);
    virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
114
silverburgh

ハーブサッターは非常にうまく説明しました ここ

ガイドライン#2:仮想関数をプライベートにすることをお勧めします。

これにより、派生クラスが関数をオーバーライドして、必要に応じて動作をカスタマイズできます。派生クラスから呼び出すことができるように仮想関数を直接公開することなく(関数が保護されている場合のみ可能)。ポイントは、カスタマイズを可能にする仮想関数が存在することです。派生クラスのコード内から直接呼び出す必要がある場合を除き、プライベートクラス以外のクラスにする必要はありません。

111
Prasoon Saurav

メソッドが仮想の場合、プライベートであっても、派生クラスによってオーバーライドできます。仮想メソッドが呼び出されると、オーバーライドされたバージョンが呼び出されます。

(Prasoon Sauravの答えで引用されたHerb Sutterに反対して、C++ FAQ Lite プライベート仮想に推奨 。これは主に人々を混乱させるためです。)

62
sth

最初にこの概念に出会ったのは、Scott Meyersの「Effective C++」、項目35:仮想関数の代替を検討してください。興味のある人のためにScott Mayersを参照したかったからです。

Non-Virtual Interfaceイディオムを介したテンプレートメソッドパターンの一部です:パブリックフェーシングメソッドは仮想ではありません。むしろ、プライベートな仮想メソッド呼び出しをラップします。基本クラスは、プライベート仮想関数呼び出しの前後にロジックを実行できます。

public:
  void NonVirtualCalc(...)
  {
    // Setup
    PrivateVirtualCalcCall(...);
    // Clean up
  }

これは非常に興味深いデザインパターンだと思います。追加されたコントロールがどのように役立つかがわかると思います。

  • 仮想関数privateを作成する理由一番の理由は、public向きのメソッドを既に提供していることです。
  • 他の興味深いことにメソッドを使用できるように、単純にprotectedにしないのはなぜですか?私はそれが常にあなたのデザインとベースクラスがどのように適合すると信じるかに依存すると思います。派生クラスメーカーは必要なロジックの実装に集中すべきだと主張します。他のすべてはすでに処理されています。また、カプセル化の問題もあります。

C++の観点から見ると、プライベート仮想メソッドをクラスから呼び出すことはできなくても、プライベート仮想メソッドをオーバーライドすることは完全に合法です。これにより、上記の設計がサポートされます。

8
Pooven

それらを使用して、派生クラスが基本クラスの「空白を埋める」ことを可能にし、そのような穴をエンドユーザーに公開しません。たとえば、共通のベースから派生した非常にステートフルなオブジェクトがあり、ステートマシン全体の2/3のみを実装できます(派生クラスはテンプレート引数に応じて残りの1/3を提供し、ベースはその他の理由)。

多くのパブリックAPIを正しく機能させるために共通の基底クラスが必要です(可変長テンプレートを使用しています)が、そのオブジェクトを公開することはできません。さらに悪いことに、クレーターを純粋な仮想関数の形で「プライベート」以外の状態マシンに置いた場合、子クラスの1つから派生した賢いまたは無知なユーザーが、ユーザーが決して触れてはならないメソッドをオーバーライドできます。そこで、ステートマシンの「頭脳」をPRIVATE仮想関数に入れました。その後、基本クラスの直接の子は非仮想オーバーライドの空白を埋め、ユーザーは結果のオブジェクトを安全に使用するか、ステートマシンを台無しにすることなく独自の派生クラスを作成できます。

パブリック仮想メソッドを持たせてはいけないという議論については、BSと言います。ユーザーは、プライベートクラスをパブリッククラスと同様に簡単に不適切にオーバーライドできます。結局、新しいクラスを定義しているのです。パブリックが特定のAPIを変更してはならない場合、パブリックにアクセス可能なオブジェクトでは仮想AT ALLにしないでください。

3
Zack Yezek