私は最近、C++ では純粋仮想関数が必要に応じて本体を持つことができることを知りました。
そのような機能の実際の使用例は何ですか?
クラシックは純粋な仮想デストラクタです。
class abstract {
public:
virtual ~abstract() = 0;
};
abstract::~abstract() {}
他に何もすることがないので純粋にし、クラスを抽象化したいが、派生クラスのデストラクタが明示的に呼び出すため、実装を提供する必要があります。ええ、私は知っています、かなりばかげた教科書の例ですが、それ自体は古典です. The C++ Programming Language の初版に含まれていたに違いありません。
とにかく、純粋な仮想関数を実装する機能が本当に必要だったことを思い出せません。私には、この機能が存在する唯一の理由は、明示的に禁止する必要があり、Stroustrup がその理由を認識していなかったためだと思われます。
この機能が必要だと感じた場合は、おそらく設計を間違った方向に進んでいる可能性があります。
本体の有無にかかわらず、純粋な仮想関数は、派生型が独自の実装を提供する必要があることを意味します。
基本クラスの純粋仮想関数本体は、派生クラスが基本クラスの実装を呼び出したい場合に役立ちます。
抽象基本クラス(純粋仮想関数を含む)が宣言する純粋仮想関数の実装を提供する理由の1つは、派生クラスに、使用することを選択できる簡単な「デフォルト」を持たせるためです。オプションでオーバーライドできる通常の仮想関数に比べて、これにはそれほど多くの利点はありません。実際、唯一の本当の違いは、派生クラスに「デフォルト」の基本クラス実装の使用について明示的に強制していることです。 :
class foo {
public:
virtual int interface();
};
int foo::interface()
{
printf( "default foo::interface() called\n");
return 0;
};
class pure_foo {
public:
virtual int interface() = 0;
};
int pure_foo::interface()
{
printf( "default pure_foo::interface() called\n");
return 42;
}
//------------------------------------
class foobar : public foo {
// no need to override to get default behavior
};
class foobar2 : public pure_foo {
public:
// need to be explicit about the override, even to get default behavior
virtual int interface();
};
int foobar2::interface()
{
// foobar is lazy; it'll just use pure_foo's default
return pure_foo::interface();
}
非常に多くのメリットがあるかどうかはわかりません。おそらく、設計が抽象クラスで始まり、その後、派生した具象クラスの多くが同じ動作を実装していることがわかったため、その動作を移動することにしました。純粋仮想関数の基本クラスの実装に。
派生クラスが変更/拡張/拡張することが期待される可能性がある純粋仮想関数の基本クラスの実装に共通の動作を組み込むことも合理的であると思います。
C++ 標準委員会の元議長である全能の Herb Sutter は、純粋仮想メソッドの実装を提供することを検討できる 3 つのシナリオを示しました。
個人的にはそう言わざるを得ません - 私はそれらのどれも説得力があるとは思わず、一般的にこれは C++ のセマンティックの疣贅の 1 つだと考えています。C++ は、抽象親 vtables を作成して分解するために道を踏み外しているようで、子の構築/破棄中にそれらを簡単に公開するだけでなく、コミュニティの専門家は満場一致でそれらを使用しないことを推奨しています。
ユース ケースの 1 つは、クラスのコンストラクターまたはデストラクターから純粋仮想関数を呼び出すことです。
本体を持つ仮想関数と本体を持つ純粋な仮想関数の唯一の違いは、インスタンス化を防止する秒の存在です。C++ でクラス抽象をマークすることはできません。