C ++関数のオーバーライド
-
06-07-2019 - |
質問
3つの異なる基本クラスがあります:
class BaseA
{
public:
virtual int foo() = 0;
};
class BaseB
{
public:
virtual int foo() { return 42; }
};
class BaseC
{
public:
int foo() { return 42; }
};
次に、このようなベースから派生します(A、B、またはCをXに置き換えます):
class Child : public BaseX
{
public:
int foo() { return 42; }
};
3つの異なる基本クラスで関数はどのようにオーバーライドされますか?次の3つの仮定は正しいですか?他に注意点はありますか?
- BaseAでは、子クラスはコンパイルされず、純粋な仮想関数は定義されません。
- BaseBでは、BaseB *またはChild *でfooを呼び出すと、子の関数が呼び出されます。
- BaseCでは、Child *でfooを呼び出すときに子の関数が呼び出されますが、BaseB *では呼び出されません(親クラスの関数が呼び出されます)。
解決
派生クラスでは、キーワードvirtualが派生クラスのメソッドで使用されていなくても、基本クラスで仮想として定義されている場合、メソッドは仮想です。
-
BaseA
を使用すると、foo()
が仮想でクラスChild
で実行され、意図したとおりにコンパイルおよび実行されます。 -
BaseB
と同じで、意図したとおりにコンパイルおよび実行されます。foo()
はvirtual()で、クラスChild
で実行されます。 - ただし、
BaseC
を使用すると、コンパイルおよび実行されますが、BaseC
のコンテキストから呼び出すと、BaseC
バージョンが実行されます、およびChild
のコンテキストで呼び出す場合はChild
バージョン。
他のヒント
覚えておくべき重要なルールは、関数が仮想として宣言されると、派生クラスで一致するシグネチャを持つ関数は常に仮想です。したがって、Aの子とBの子についてはオーバーライドされますが、これらは同じように動作します(例外として、BaseAを直接インスタンス化することはできません)。
ただし、Cでは、関数はオーバーライドされず、オーバーロードされます。その状況では、静的型のみが重要です。オブジェクトが実際に何であるか(動的型)ではなく、(静的型)へのポインタで呼び出されます
BaseAでは、子クラスは コンパイル、純粋仮想関数 定義されていません
これは、BaseAのオブジェクトを作成しようとした場合にのみ当てはまります。 Childのオブジェクトを作成し、BaseA *またはChild *のいずれかを使用してfoo()を呼び出すことができる場合
BaseBでは、子の関数 BaseB *でfooを呼び出すときに呼び出されます またはChild *。
オブジェクトはBaseBまたはChildのいずれかであるため、オブジェクトのタイプに依存します。オブジェクトがBaseBの場合、BaseB :: fooが呼び出されます。
BaseCでは、子の関数 Child *でfooを呼び出すときに呼び出されます ただし、BaseB *(関数 親クラスが呼び出されます)。
はい、しかしあなたは決してこれをしたくありません。
ポリモーフィズムの観点からは、Aを好むので、各子には仮想関数の独自の実装があることがわかります。
有効なデフォルト実装がある場合は主にBを選択しますが、必要に応じてすべての子クラスに独自の実装があることを確認する必要があります。
Cは多態性ではないため、慎重に使用してください。
ほとんどの場合、呼び出し方によって異なります。
実行した場合:
class Child : public BaseA
{
public:
int foo() { return 42; }
};
およびした
BaseA baseA = new Child();
baseA->foo();
Childのfoo関数を呼び出します。
ただし、これを行った場合:
BaseA baseA = new BaseA();
コンパイル時にエラーが発生します。
クラスの子は コンパイルします。そのタイプのオブジェクトをインスタンス化することはできません。
これは、Baseの一部の関数をオーバーライドしてから再度派生する場合に役立ちます。