私はいくつかのコードでこれを見つけました:
class Foo {
[...]
private:
virtual void Bar() = 0;
[...]
}
これには何か目的がありますか?
(私はいくつかのコードを VS から G++ に移植しようとしていますが、これが私の注意を引きました)
私はいくつかのコードでこれを見つけました:
class Foo {
[...]
private:
virtual void Bar() = 0;
[...]
}
これには何か目的がありますか?
(私はいくつかのコードを VS から G++ に移植しようとしていますが、これが私の注意を引きました)
なぜそのようなことをしたいのかについては、この Herb Sutter の記事を参照してください。
これはたまたまプライベートな純粋仮想関数です。これにより、派生クラスがメソッドを実装する必要があります。この場合はバー。
これはC++で「インターフェース」を作成するために行われ、多くの場合、人々はこれらをパブリックと考えているため、混乱する可能性があると思います。呼び出される順序を保証するために、パブリック メソッドがこれらのプライベート メソッドを使用するプライベートなインターフェイスを定義したい場合があります。(これはテンプレートメソッドと呼ばれていると思います)
比較的悪い例:)
クラス RecordFile { 公衆: RecordFile(const std::string &filename); void process(const Record &rec) { // 派生クラス関数を呼び出して除外します // このクラスの派生インスタンスが行うことを記録します // 気にしない if (filterRecord(rec)) { writeRecordToFile(rec); } }; プライベート: // レコードが重要な場合は true を返します // 保持する必要があります virtual bool filterRecord(const Record &rec) = 0; void writeRecordToFile(const レコード &rec); };
ISO C++ 2003 では明示的に許可されています。
§10.3 は、アクセス指定子について何も述べておらず、仮想関数のオーバーライドのコンテキストで述べている 2 番目の句に脚注も含まれています。
[...] アクセス制御 (第 11 節) は、オーバーライドを決定する際に考慮されません。
コードは完全に合法です。
よくまとめられているすばらしいC++ FAQ Liteから簡単な説明を引用します。
[23.4] いつプライベート バーチャルを使用する必要がありますか?
ほとんどは決してない。
保護された仮想は問題ありませんが、プライベート仮想は通常、純損失になります。理由: プライベート仮想は新しい C++ プログラマーを混乱させ、混乱はコストを増加させ、スケジュールを遅らせ、リスクを低下させます。
新しい C++ プログラマーは、プライベート仮想はオーバーライドできないと考えているため、プライベート仮想に混乱します。結局のところ、派生クラスはその基本クラスでプライベートなメンバーにアクセスできないため、どのようにしてその基本クラスからプライベート仮想をオーバーライドできるのでしょうか? 上記については説明がありますが、それは学術的なものです。本当の問題は、ほとんどの人が最初にプライベート仮想環境に遭遇したときに混乱することであり、混乱は悪いことです.
やむを得ない理由がない限り、プライベート バーチャルは避けてください。
その間、C++ FAQ Lite が更新されました。
ところで、ほとんどの初心者の C++ プログラマーは、プライベート仮想が無効になる可能性があり、ましてや有効であることに混乱します。基本クラスのプライベート メンバーは、そこから派生したクラスではアクセスできないと教えられましたが、これは正しいことです。ただし、派生クラスによるこのアクセス不能は、派生クラスに対する仮想呼び出しメカニズムとは何の関係もありません。これは初心者を混乱させる可能性があるため、C++ FAQ では以前、プライベート仮想ではなく保護仮想を使用することを推奨していました。ただし、プライベート仮想アプローチは現在十分に一般的であるため、初心者の混乱はそれほど懸念されていません.
通常の「学問的な」答えは、アクセス指定子と仮想性は直交しており、一方が他方に影響を与えないというものです。
もう少し実用的な答え: プライベート仮想関数は、テンプレート メソッドデザイン パターンを実装するためによく使用されます。プライベート仮想関数をサポートしない言語では、テンプレート メソッドをパブリックにする必要がありますが、実際にはインターフェイスの一部になることを意図していません。
純粋仮想関数です。「Foo」から派生した最終的な実装は、「Bar」関数を実装する必要があります。
これにより、関数は仮想ではなく純粋仮想になります。
デフォルトでは実装は提供されず、継承クラスによって関数の実装を指定する必要があるという意図があります。ただし、これはオーバーライドできます。
このように、すべてのメンバー関数が純粋仮想として指定されている完全なクラスが時々見られます。
これらは抽象基本クラスであり、インターフェイス クラスと呼ばれることもあります。ABC の設計者は、「この基本クラスのすべての特殊化に対してこの機能を実装する方法がわかりました。ただし、すべての機能が必要です。これらは特殊化が機能するように定義されており、オブジェクトがどのように動作するかを知っています。」
編集:おっと、メンバーの純粋な仮想関数がプライベートであるという事実を見つけました。(マイケルに感謝) これで少し状況が変わります。
この基本クラスがプライベート継承を使用して継承されると、状況が変わります。基本的に、基本クラスの設計者が行っていることは、派生クラスが基本クラスで非プライベート関数を呼び出すときです。動作の一部は、派生クラスの関数の特殊化に委譲されています。非プライベート メンバーは「何か」を実行しており、その「何か」の一部は、純粋な仮想基本クラス関数を介した実装への呼び出しです。
したがって、Foo の一部のパブリック関数は Foo 内で Bar 関数を呼び出しており、特定のケースに合わせて Bar 関数の特殊な実装を提供するという事実に依存しています。
Scott Meyers は、これを「実装された」と呼んでいます。
ところで、質問の「細字」も見なかった人々によってすぐに削除された回答の数について、ただ笑っています! (-:
HTH
乾杯、
それが役立つと思われる唯一の目的は、共通のインターフェースを提供することです。
ところで、関数がプライベート仮想として宣言されていても、クラス インスタンスまたはフレンドから実装して呼び出すことができます。
とはいえ、この種のものは通常、インターフェースとして機能することを意味しますが、私はこのようにはしません。