3

私はここでC++パズルを読んでいます:http://gotw.ca/gotw/005.htm

静的過負荷解決と動的過負荷解決(またはデフォルトのパラメーター)に関する彼の説明を理解していなかったので、問題を抽出して、自分でいくつかのテストを作成しようとしました。

class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
};

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(double a) {cout << "derived/int" << endl;}
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);
}

出力は次のとおりです。

derived/no parameters
base/int

の呼び出しでfoo()、C ++はそれがを指していることを認識しているように見えDerivedますが、呼び出しでは、C ++はクラス内の関数を認識してfoo(1.0)いませんか?void foo(double a)Derived

私の考えでは、C ++には最初の呼び出しを説明するポリモーフィズムがありますが、過負荷の解決は2番目の呼び出しを説明するコンパイル時に行われるという競合する考えがあります。

4

6 に答える 6

3

これは、関数非表示の古典的な例です。
派生クラスの関数は、次の場合にのみBaseクラス関数を オーバーライドします。

  1. virtualキーワードは、Baseクラス関数に少なくとも存在します。
  2. Derivedクラスの関数は、Baseクラスの関数とまったく同じシグネチャを持っています。

2番目のルールには、共変リターンタイプが許可される 例外があります。

上記の2つのルールを考えると:

foo()派生クラスのnoパラメーター関数はBaseクラスをオーバーライドfoo()するため、動的ディスパッチは期待どおりに機能します。

foo(double)1つのパラメーターを持つバージョンは、Baseクラス関数をオーバーライドfoo(int)せず、単に非表示にします。オーバーライドがないため、動的ディスパッチはありません。コンパイラfoo(int)は、Baseクラスのスコープで見つかった関数を呼び出すだけです。

于 2012-02-03T06:04:08.590 に答える
2

ptrタイプですBase*

Baseパラメータ1.0として使用する唯一の関数はですvirtual void foo(int a)

ここで、関数を仮想的にオーバーライドするには、署名と完全に一致する必要があることを覚えておいてください(分散を差し引いたものですが、あなたの場合には適用されません)。オーバーライドするのではなくfoo(int)、実際に新しいを作成しfoo(double)ます。

于 2012-02-03T06:11:05.343 に答える
2

C ++はvoid foo(double a)Derivedクラスの関数を見ませんか?

C ++は関数を認識しますが、関数シグネチャの違いにより、関数とは関連付けられていませんBase::foovirtual

virtual void Base::foo(int);  // 'Base' signature
void Derived::foo(double);    // 'Derived' signature

したがって、ここには2つの重要な事実がありますDerived::foo(double)

  1. に関連しない(オーバーライドする)Base::foo(int)
  2. 方法ではありませんvirtual(それを作ってvirtualも役に立ちません)

あなたが電話するとき、最初のポイントはより重要です

// 'ptr' refers 'Base' method signature; so 'double' implicitly converts to 'int'
ptr->foo(1.0);

Baseポインタが使用されます。vtableリストには、のエントリが1つだけありBase::foo(int)ます。したがって、それは呼ばれます。

于 2012-02-03T06:03:34.110 に答える
1

C ++は、クラス内の署名(呼び出し元)で仮想関数をオーバーライドしていないvoid foo(double a)ため、Derivedクラス内を認識できません。void foo(double a)Base

void foo(int a)クラスにはがありBaseますが、C++のルールによるとまったく異なる関数です。


一方、クラスvoid foo()内のは、両方が同じ署名を持っているため、クラス内Derivedの仮想関数をオーバーライドしています。void foo()Base

于 2012-02-03T06:02:06.603 に答える
1
class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
        };

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(int a) {cout << "derived/int" << endl;}
     //  then your derived class function   will call 
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);

}
于 2012-02-03T06:26:12.763 に答える
0

静的vs動的過負荷解決!!! ここではどういう意味ですか?

オーバーロードは常に静的にバインドされ、関数はクラス内で定義されます(1つの関数が基本クラスにあり、他の関数が派生クラスにあるわけではありません)。

したがって、foo(double a)とfoo(int a)はオーバーロードされません。同時に、署名が異なるため、これらは上書きされません。そのため、ステートメントptr-> foo(1.0)に対して仮想メカニズムは実行されていません。

于 2012-02-03T06:36:48.490 に答える