22

iffooが classDで宣言されていて、virtual とマークされていない場合、次のコードはfooinの実装を呼び出します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
4

4 に答える 4

24

標準 10.3.2 (class.virtual) は次のように述べています。

仮想メンバー関数 vf がクラス Base およびクラス Derived で宣言され、Base から直接的または間接的に派生した場合、Base::vf と同じ名前と同じパラメーター リストを持つメンバー関数 vf が宣言され、Derived::vf仮想でもあり(宣言されているかどうかに関係なく)、オーバーライドします*

[脚注: 仮想関数と同じ名前で異なるパラメーター リスト (clause over) を持つ関数は、必ずしも仮想関数ではなく、オーバーライドしません。オーバーライド関数の宣言での仮想指定子の使用は合法ですが、冗長です (空のセマンティクスがあります)。アクセス制御 (節 class.access) は、オーバーライドを決定する際に考慮されません。--- 脚注終了]

于 2009-09-10T11:53:54.920 に答える
17

即答は「いいえ」かもしれませんが、正しい答えは「はい」です

C++ は関数の隠蔽について認識していないため、virtual キーワードを使用せずに仮想関数をオーバーライドすると、その関数も仮想としてマークされます。

于 2009-09-10T11:46:32.690 に答える
0

e のオブジェクトのコピーを作成して d に入れているわけではありません。したがって、d.foo() は通常のポリモーフィック動作に従い、派生クラス メソッドを呼び出します。基本クラスで仮想として宣言されたメソッドは、派生クラスでも自動的に仮想になります。

于 2009-09-10T11:48:08.600 に答える
-1

出力 ("E") は、期待どおりに動作します。

理由: その参照の動的 (つまりランタイム) 型は E です。D への静的アップキャストを行っていますが、もちろんオブジェクトの実際の型は変更されません。

これこそが、仮想メソッドと動的ディスパッチの背後にある考え方です。インスタンス化していた型 (この場合は E) の動作が表示されます。

于 2009-09-10T11:51:34.003 に答える