C ++では、仮想関数をオーバーライドする場合、関数は自動的に仮想化されますか?
-
05-07-2019 - |
質問
foo
がクラス D
で宣言されているが、仮想とマークされていない場合、次のコードは foo
D
で( d
の動的タイプに関係なく)。
D& d = ...;
d.foo();
ただし、次のプログラムではそうではありません。誰でもこれを説明できますか?仮想関数をオーバーライドする場合、メソッドは自動的に仮想ですか?
#include <iostream>
using namespace std;
class C {
public:
virtual void foo() { cout << "C" << endl; }
};
class D : public C {
public:
void foo() { cout << "D" << endl; }
};
class E : public D {
public:
void foo() { cout << "E" << endl; }
};
int main(int argc, char **argv)
{
E& e = *new E;
D& d = *static_cast<D*>(&e);
d.foo();
return 0;
}
上記のプログラムの出力は次のとおりです。
E
解決
Standard 10.3.2(class.virtual)のコメント:
仮想メンバー関数vfがクラスBaseおよびクラスDerivedで宣言され、Baseから直接または間接的に派生した場合、Base :: vfと同じ名前と同じパラメーターリストを持つメンバー関数vfが宣言され、その後Derived :: vfも(そのように宣言されているかどうかに関係なく)仮想であり、オーバーライドします*
[脚注:仮想関数と同じ名前で異なるパラメーターリスト(句)を持つ関数は、必ずしも仮想であるとは限らず、オーバーライドされません。オーバーライド関数の宣言での仮想指定子の使用は正当ですが、冗長です(空のセマンティクスがあります)。アクセス制御(class.access節)は、オーバーライドの決定では考慮されません。 --- foonoteを終了]
他のヒント
クイックアンサーは「いいえ」の場合もありますが、正解は「はい」です
C ++は関数の非表示を認識しないため、仮想キーワードなしで仮想関数をオーバーライドすると、その関数も仮想になります。
eのオブジェクトのコピーを作成してdに配置することはありません。したがって、d.foo()は通常のポリモーフィックな動作に従い、派生クラスメソッドを呼び出します。基本クラスで仮想として宣言されているメソッドは、派生クラスでも自動的に仮想になります。
出力(&quot; E&quot;)は、期待どおりに動作します。
理由: その参照の動的(つまり実行時)型はEです。Dへの静的なアップキャストを行っていますが、オブジェクトの実際の型はもちろん変更しません。
それが仮想メソッドと動的ディスパッチの背後にあるまさにその考え方です。インスタンス化した型、この場合はEの動作がわかります。