防止の仮想メソッドの実装で、C++
-
23-08-2019 - |
質問
私は、以下のクラス階層のC++:
class Base {
virtual void apply() = 0;
};
class Derived : public Base {
virtual void apply() {
// implementation here that uses derived_specialty
}
virtual void derived_specialty() = 0;
};
class Implementation : public Derived {
virtual void derived_specialty() {
// implementation
}
};
いるという保証の授業のレベルの実施な供給独自の実装の適用そのもののみを実施derived_specialty.必要があります。を保証する授業を受け継ぎから派生しませんの実施適用し、その由来:象となる実装が使われるのか?私の理解では、C++、仮想の基底クラスが仮想の下、継承階層があ技C++の達成にも興味を聞いてきました。
私は常に驚いたのは大変なことは、C++していかないといけないと思いましたと思います。:)
解決
できるような構成:
class Base {
virtual void apply();
};
class Derived : public Base {
class IImplementation {
virtual void derived_specialty() = 0;
};
IImplementation& m_implementation;
Derived(IImplementation& implementation)
: m_implementation(implementation)
{}
virtual void apply() {
// implementation here that uses m_implementation.derived_specialty
}
};
class Implementation : Derived::IImplementation {
virtual void derived_specialty() {
// implementation
}
};
その他のクラスもサブクラスからオーバーライドの適用方法ものの、実装クラスがなくなれます。
他のヒント
あなたは実装委譲クラスではなく派生
の専門作ることができますclass Derived : public Base
{
Derived()
void apply()
{
//whatever, delegate to impl class instance
impl->apply_specialization();
}
Impl* impl;
};
class Impl : public WhateverImplInterface
{
void apply_specialization(){}
};
次に実装が適用機能へのアクセス権を持っていないと階層から分離されています。派生クラスは、その後のImplクラスのインスタンスによってパラメータ化される。
あなたのドキュメントに制限を明確にします。
「私は実装のレベルでクラスが適用され、独自の実装を提供しないことを保証したいと思います。」
あなたがすることはできません。
私はこれまで、独自の関数を適用定義から派生したクラスのいずれかを防ぐ見てきた例のなし。彼らはすべて、彼らがをすることをユーザーに示唆、適用とderived_specialtyとの関係をモデル化するための方法を提供していないのオーバーライドが適用されるべきです。あなたはしかし、ドキュメンテーションのラインで同じことを達成することができます。
あなたが探しているのは右、C ++には存在しないのですか?
Javaの最後の文でありますあなたは::ベースを作る非仮想適用し、あまりにも基地内のテンプレートメソッドパターンを使用することができます。
この記事では、この練習の利点を説明します。
http://www.gotw.ca/publications/mill18.htmする
あなたは必ず、の適用のが上書きされなかった作るためにデストラクタでアサーションを置くことができます
class Base {
virtual void apply() = 0;
};
class Derived : public Base {
virtual void apply() {
// implementation here that uses derived_specialty
}
virtual ~Derived() {
assert(this->apply == Derived::apply);
}
virtual void derived_specialty() = 0;
};
class Implementation : public Derived {
virtual void derived_specialty() {
// implementation
}
};
派生しながら、ここでの考え方はthis->が適用されることで、仮想テーブルからメソッドのアドレスを取得します::適用するには、コンパイル時に、それを解決します。それらが等しい場合は、実装クラスで再び上書きされなかった適用されます。このアプローチはまた、それがアサート()マクロは(あるべきで)生成されたコードから取り除かれるリリースビルドにもパフォーマンスペナルティを課さないという利点を有する。
タグテンプレートメソッドパターンを使用してみてください
ウィキペディアには、C ++の例があります。
これは、カプセル化を変更しませんが、あなたがする必要はありませんので、それはデザインを改善します。
アクセス修飾子は常にあります:
class base {
protected: virtual void real_apply() = 0;
};
class derived : public base {
void real_apply();
public:
apply() { real_apply(); }
};
class other : public derived {
void func() {
apply(); // this is ok
real_apply(); // this is a compile time error
}
};