1

次のコードでは、出力が Bf Bf DD.f であると予想されますが、代わりに取得される出力は Bf Bf DDBfDですf

class B
{
public:
    void f() { cout << "B.f "; }
};

class D : public B
{
public:
    virtual void f() { cout << "D.f "; }
};

class DD : public D{
public:
    virtual void f() { cout << "DD.f "; }
};

B * b = new B();
B * d = new D();
B * dd = new DD();

b->f();
d->f();
dd->f();
4

5 に答える 5

4

関数virtualは、宣言virtualされたレベルからなります。最初に で宣言f virtualしますD。これは、動的ディスパッチがD上からのみ発生することを意味します。B派生クラスについては知りませんし、知っておくべきでもありません。

コンパイラがそれをどのように認識するかを考えてみてください。

You have a pointer to B-B次の定義があります:

class B
{
public:
    void f() { cout << "B.f "; }
};

fそうではないので、virtual先に進んで呼び出しを静的に解決しますB::f()

于 2013-01-28T12:11:09.137 に答える
2

へのポインターから動的ディスパッチを機能させるには、 を仮想B化する必要があります。f()B

class B
{
public:
    virtual void f() { cout << "B.f "; }
};
于 2013-01-28T12:09:39.927 に答える
1

B::f()仮想に設定する必要があります。仮想に設定B::f()しないと、B 仮想テーブル (vtbl) に表示されないためB::f()、派生クラスへの呼び出しをディスパッチする代わりに呼び出されます。

class B
{
public:
   virtual void f() { cout << "B.f "; }
};
于 2013-01-28T12:09:50.650 に答える
0

Bでf()virtualを宣言するとすぐに、これは、派生クラスの同じ名前の他のすべての関数の関数ポインターを保持する仮想テーブルの維持を開始します。これは、動的/遅延バインディング方式で関数呼び出しを解決するために使用されるルックアップテーブルです。

于 2013-01-28T12:29:31.303 に答える
0

参照またはポインターを使用してメソッドを呼び出す場合、コンパイラーはメソッドの宣言でポインターまたは参照の型を検索します (ここでは、Bsignature を持つメソッドの宣言を検索しますf())。見つかった場合:

  • としてマークされていない場合はvirtual、このクラスに定義されたメソッドへの呼び出しとして解決します - これは静的バインディングです。
  • としてマークされている場合virtual、呼び出されるメソッドは、参照またはポイントされるオブジェクトの適切なメソッドになります。これは動的バインディングです。

次のテストは次のようになります。

DD * dd = new DD();
D * d = dd;
B * b = d;

b->f();
d->f();
dd->f();

異なる方法で使用/表示される1 つのオブジェクトnew DD()... 各タイプは、オブジェクトに対する一種のビューと考えることができます。Bそれを として見ると、何かをしますが、常に同じことをしますが、またはf()として見ると、何か違うことをします...DDDf()

通りで誰かに会った場合、彼があなたに挨拶する標準的な方法は、こんにちはと言うことですが、同じ人が彼の友人に会ったとき、彼は挨拶することができます! またはよ!:

class Person {
public:
  void salute() { cout << "Hello" << endl; }
};
class Friend : public Person {
public:
  virtual void salute() { cout << "Hi!" << endl; }
};
class RoomMate : public Friend {
public:
  virtual void salute() { cout << "Yo!" << endl; }
};
void asACustomer(Person &p) {
   p.salute(); // static binding, we need the standard politeness
}
void asAFriend(Friend &f) {
    p.salute(); // dynamic binding, we want an appropriate message...
}
RoomMate joe;
asCustomer(joe);
asFriend(joe);

静的バインディングを使用すると、コンパイル時にどのメソッドが呼び出されるかがわかります。動的バインディングではできません。適切なバインディングがあることだけがわかります。これは、サブタイピング ポリモーフィズムの重要なポイントです。

一般に、メソッドの静的バインディングと動的バインディングを混在させる場合は注意が必要です。

于 2013-01-28T18:32:57.933 に答える