すべてのクラスをマルチレベルの継承階層で「純粋仮想」メソッドを実装/上書きするように強制する
-
13-11-2019 - |
質問
C ++では、 pure virtual
メソッドは、その強制的にのみのみ(オブジェクトの作成のために)を義務付けていますが、壮大な子供などにはそうではありませんか?
.
struct B {
virtual void foo () = 0;
};
struct D : B {
virtual void foo () { ... };
};
struct DD : D {
// ok! ... if 'B::foo' is not overridden; it will use 'D::foo' implicitly
};
この機能を離れることに大きな取引を見ていません。
たとえば、言語デザインの観点では、struct DD
のような明示的なステートメントがある場合にのみ、D::foo
がusing D::foo;
を使用できるようになる可能性がありました。それ以外の場合は、foo
必須をオーバーライドする必要があります。
C ++にこの効果を持つ実用的な方法はありますか?
解決
私は1つのメカニズムを見つけました、少なくとも私たちは上書きされたメソッドを明示的にを発表するように求められます。それは完璧な方法ではありませんが、少なくとも幾分近く。
SUSSANOS、virtual
(Base)には純粋なclass B
メソッドがほとんどありません:
.
class B {
virtual void foo () = 0;
virtual void bar (int) = 0;
};
その中で、foo()
全体が階層全体でオーバーライドされるようにしておくことをお勧めします。の抽象的なfoo()
1レベルアップ
.
class Register_foo {
template<typename T> // this matches the signature of 'foo'
Register_foo (void (T::*)()) {}
};
class Base : public virtual Register_foo { // <---- virtual inheritance
virtual void bar (int) = 0;
Base () : Register_foo(&Base::foo) {} // <--- explicitly pass the function name
};
階層内のそれに続くすべての子クラスは、 の 明示的にの内部に register を持つことになります。 e.g。:
.
struct D : B {
D () : Register_foo(&D::foo) {}
D (const D &other) : Register_foo(&D::foo) {}
virtual void foo () {};
};
この登録メカニズムは、ビジネスロジックとは関係ありません。しかし、少なくとも子供クラスのコンストラクターの内部では、それが使用しているfoo
です。
ただし、Child foo
は、独自のclass
またはその親のfoo
を使用して登録することを選択できますが、少なくとも発表を明示的に発表しました。
他のヒント
基本的に求めていることは、最も派生したことを要求することです。
クラスは機能を実装します。そして私の質問は:なぜですか?唯一の唯一の
これを関連性があると想像できる時間は、clone()
のような関数です。
another()
。同じタイプの新しいインスタンスを返します。そしてそれです
あなたが本当に執行したいもの、新しいインスタンスが同じこと
タイプ;機能が実際に実装されている場合でも
無関係です。そしてあなたはそれを強制することができます:
class Base
{
virtual Base* doClone() const = 0;
public:
Base* clone() const
{
Base* results = doClone();
assert( typeid(*results) == typeid(*this) );
return results;
}
}
.
(実際には、clone
を上書きするのを忘れていることを決して見つけなかった
本当の問題になるので、私は上記のようなものに悩まされませんでした。
しかし、それは一般的に役立つ技術ですが、いつでも執行したいと思う
後処理)
純粋な仮想とは、インスタンス化されるべきことを意味し、純粋な仮想関数を宣言するクラスの の子孫でオーバーライドされなければなりません。これは、純粋な仮想を宣言するベースとインスタンス化されているベースの間の中間クラスにあるクラスまたは中間クラスにあることがあります。 ただし、純粋な仮想をオーバーライドすることなく、純粋な仮想を持つものから派生する中間クラスを持つことはまだ可能です。純粋な仮想を宣言するクラスのように、それらのクラスはベースのクラスとしてのみ使用できます。これらのクラスのインスタンスを作成することはできません。これからのクラスだけが、すべての純粋な仮想が実装されています。
子孫が仮想を上書きする必要は、中間クラスがすでに行われていても、答えはNO、C ++は少なくともそれをすることを意図しているものは何も提供しません。それは、複数の(おそらく仮想的な)継承を使用して一緒に何かをハッキングすることができるかもしれないように、中間クラスの実装が存在しているがそれを使用しようとしているように、それを曖昧にすることを試みるようにすることができるように思われるが、私は確かに十分にそれを通してそれを考えていないことそれがうまくいかに(またはIF)しても、それが行ったとしても、それは問題の関数を呼び出すことだけで、オブジェクトをインスタンス化しようとしているだけではありません。
あなたの例では、D::foo
Pureを宣言していません。それが上書きされる必要がない理由です。再度上書きする必要がある場合は、それを純粋に宣言してください。
D
をインスタンス化できるが、それ以上の派生クラスをfoo
をオーバーライドするように強制することはできません。ただし、純粋に宣言したD
からさらに別のクラスを派生させることができ、から派生したクラスは再び上書きされなければなりません。
C ++にこの効果を持つ実用的な方法はありますか?
いいえ、そして正当な理由で。これが標準の一部であれば、大規模プロジェクトでメンテナンスを想像してみてください。一部の基本クラスまたは中間基準クラスは、パブリックインターフェイス、抽象インタフェースを追加する必要があります。今、そのすべての子供とその孫のすべてが変更され再コンパイルされる必要があるでしょう(あなたが提案したようにd :: foo()を使って追加するのと同じくらい簡単であったとしても)、あなたはおそらくこれが見出し、地獄の台所である場所を見るでしょう。
実際に実装を強制したい場合は、子クラス内の他の純粋な仮想の実装を強制することができます。これはCRTPパターンも使用することもできます。