回答:
純粋なvirtual
関数は、直接インスタンス化される派生型で実装する必要がありますが、基本型でも実装を定義できます。(呼び出すことによって、(アクセス権限で許可されている場合)派生クラスが明示的に完全スコープ名を使用して、基本クラスの実装を呼び出すことができますA::f()
-場合はあなたの例ではA::f()
なかったですpublic
かprotected
)。何かのようなもの:
class B : public A {
virtual void f() {
// class B doesn't have anything special to do for f()
// so we'll call A's
// note that A's declaration of f() would have to be public
// or protected to avoid a compile time problem
A::f();
}
};
私が頭の中で考えることができるユースケースは、多かれ少なかれ妥当なデフォルトの動作がある場合ですが、クラスの設計者はデフォルトのような動作が明示的にのみ呼び出されることを望んでいます。また、派生クラスが常に独自の作業を実行するだけでなく、共通の機能セットを呼び出すこともできます。
言語で許可されていても、私が一般的に使用しているものではないことに注意してください(それが可能であるという事実は、ほとんどのC ++プログラマー、経験豊富なプログラマーでも驚きます)。
明確にするために、何が0であるかを誤解しています。仮想関数の後を意味します。
= 0は、派生クラスが実装を提供する必要があることを意味します。基本クラスが実装を提供することはできません。
実際には、仮想関数を純粋(= 0)としてマークすると、誰かがBase :: Function(...)を介して明示的に呼び出さない限り、または基本クラスのコンストラクターが問題の仮想関数を呼び出します。
この方法の利点は、派生型がメソッドをオーバーライドすることを強制するだけでなく、デフォルトまたは追加の実装も提供することです。
派生クラスで実行する必要があるコードがあり、それを直接実行したくない-強制的にオーバーライドしたい場合。
あなたのコードは正しいですが、これらはすべて頻繁に使用される機能ではありませんが、通常、純粋な仮想デストラクタを定義しようとしたときにのみ見られます-その場合、実装を提供する必要があります。おもしろいのは、いったんそのクラスから派生すると、デストラクタをオーバーライドする必要がないということです。
したがって、純粋な仮想関数の1つの賢明な使用法は、純粋な仮想デストラクタを「非最終」キーワードとして指定することです。
次のコードは驚くほど正しいです:
class Base {
public:
virtual ~Base() = 0;
};
Base::~Base() {}
class Derived : public Base {};
int main() {
// Base b; -- compile error
Derived d;
}
たとえば、次のように、純粋な仮想デストラクタにボディを渡す必要があります。
読む:http : //cplusplus.co.il/2009/08/22/pure-virtual-destructor/
本体の有無にかかわらず純粋な仮想関数は、派生型が独自の実装を提供する必要があることを単に意味します。
基本クラスの純粋な仮想関数本体は、派生クラスが基本クラスの実装を呼び出したい場合に役立ちます。
'virtual void foo()= 0;' 構文は、現在のクラスにfoo()を実装できないという意味ではありません。また、派生クラスで実装する必要があるという意味でもありません。私を平手打ちする前に、ダイヤモンドの問題を見てみましょう:(暗黙のコード、気にしてください)。
class A
{
public:
virtual void foo()=0;
virtual void bar();
}
class B : public virtual A
{
public:
void foo() { bar(); }
}
class C : public virtual A
{
public:
void bar();
}
class D : public B, public C
{}
int main(int argc, const char* argv[])
{
A* obj = new D();
**obj->foo();**
return 0;
}
これで、obj-> foo()を呼び出すとB :: foo()になり、次にC :: bar()になります。
わかりました...純粋な仮想メソッドは派生クラスで実装する必要はありません(foo()はクラスCで実装されていません-コンパイラーはコンパイルします)C ++には多くの抜け穴があります。
私が助けてくれることを願っています:-)
C
例ではタイプのオブジェクトをインスタンス化することはできません。タイプのオブジェクトD
はfoo
fromの実装を取得するため、インスタンス化できますB
。
実装本体を持つ純粋な仮想メソッドを使用する重要なユースケースの1つは、抽象クラスを作成したいが、クラスに適切なメソッドがなく、純粋な仮想にする場合です。この場合、クラスのデストラクタを純粋仮想にして、そのために必要な実装(空の本体も含む)を置くことができます。例として:
class Foo
{
virtual ~Foo() = 0;
void bar1() {}
void bar2(int x) {}
// other methods
};
Foo::~Foo()
{
}
この手法は、Foo
クラスを抽象化し、その結果、クラスを直接インスタンス化することを不可能にします。同時に、Foo
クラスを抽象化するための純粋な仮想メソッドを追加していません。
deported
。(.inlまたは.cppのいずれかで、一般的なファイル命名規則を参照します)。