7

以下のコードの結果が「class B::1」になる理由を誰か説明できますか?

派生クラスの仮想メソッドが、自分自身ではなく基本クラスの既定のパラメーターを使用するのはなぜですか? 私にとって、これはかなり奇妙です。前もって感謝します!

コード:

#include <iostream>

using namespace std;

class A
{
public:
    virtual void func(int a = 1)
    {
        cout << "class A::" << a;
    }
};

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        cout << "class B::" << a;
    }
};

int main()
{
    A * a = new B;
    a->func();

    return 0;
}
4

3 に答える 3

6

thisデフォルトの引数は の静的な型(つまり、 のような変数自体の型)に従って解決されるためA&ですA& a;

例を少し変更します。

#include <iostream>

class A
{
public:
    virtual void func(int a = 1)
    {
        std::cout << "class A::" << a << "\n";
    }
};

class B : public A
{
public:
    virtual void func(int a = 2)
    {
        std::cout << "class B::" << a << "\n";
    }
};

void func(A& a) { a.func(); }

int main()
{
    B b;
    func(b);
    b.func();

    return 0;
}

次の出力が表示されます。

class B::1
class B::2

イデオンで活動中。

このため、仮想関数がデフォルト値を変更することはお勧めしません。残念ながら、この構造について警告するコンパイラは知りません。


技術的な説明は、デフォルトの引数を処理する 2 つの方法があるということです。

  • トランポリンとして機能する新しい関数を作成します。void A::func() { func(1); }
  • 呼び出しサイトで欠落している引数を追加a.func()=>a.func(/*magic*/1)

A::func前者の場合 (およびも宣言されていると仮定するvirtualと)、期待どおりに動作します。ただし、後者の形式が選択されたのは、その時点での問題virtualが予見されなかったか、利点 (あるとしても...) に直面して取るに足らないと見なされたためです。

于 2012-06-03T15:25:56.703 に答える
5

C++ のポリモーフィズムは実行時に有効になるのに対し、デフォルト パラメーターの置換はコンパイル時に有効になるためです。コンパイル時に、コンパイラはポインターが指すオブジェクトの動的な型を認識していません (また、認識しているはずもありません) a。したがって、aあなたの例ではA *.

(これは偶然にも、既定のパラメーターが実装/定義ではなくインターフェイス/ヘッダーで指定される理由でもあります。コンパイラは、既定のパラメーターを実装のマシン コードに挿入することはなく、呼び出し元のマシン コードにのみ挿入します。技術的には、既定のパラメーターは呼び出し元のプロパティであり、呼び出し元はオブジェクトの動的な型を知りません (また、知る必要もありません)。

于 2012-06-03T15:13:24.850 に答える
5

デフォルト値はコンパイル時に代入され、宣言から取得されますが、呼び出される実際の関数 (A::func または B::func) は実行時に決定されます。

于 2012-06-03T15:10:56.060 に答える