簡體   English   中英

虛函數行為異常

[英]Strange behavior with virtual functions

使用以下代碼,我希望輸出為Bf Bf DD.f,但是我得到的輸出為Bf Bf Bf當DD從具有f為虛數的D派生時,這怎么可能。

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();

函數從被聲明為virtual的級別開始變為virtual 您首先在D聲明f virtual ,這意味着動態分配將僅從D向上進行。 B沒有,也不應該知道派生類。

考慮一下編譯器如何看待它:

您有一個指向B的指針B具有以下定義:

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

由於f不是virtual ,所以我將繼續靜態解決該調用-即B::f()

為了使動態分配從指向B的指針開始工作,您需要在B中將f()虛擬化:

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

您需要將B::f()設置為虛擬,而不將B::f()為虛擬,它不會出現在B虛擬表(vtbl)中,因此調用B::f()而不是調度調用派生類。

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

在B中將f()聲明為虛擬后,這便開始維護一個虛擬表,該表包含具有相同名稱的派生類的所有其他函數的函數指針。 這是一個查找表,用於以動態/后期綁定方式解析函數調用。

當您使用引用或指針來調用方法時,編譯器會在該方法的聲明中搜索指針或引用的類型(此處,它在B搜索帶有簽名f()的某個方法的聲明)。 當找到一個:

  • 如果未將其標記為virtual ,則將其解決為對該類定義的方法的調用-這是靜態綁定。
  • 如果將其標記為virtual ,則調用的方法將是所引用或指向的對象中的合適對象之一-這是動態綁定。

下一個測試應該是:

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

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

一個單獨的對象new DD()的使用/查看方式有所不同...每種類型都可以認為是您對對象的一種查看。 如果將其視為Bf()執行某些操作,但始終是相同的,但是如果將其視為DDD ,則f()執行不同的操作...

如果您在街上遇到某人,向他致敬的標准方法是打個招呼,但對於同一個人,當他遇到他的一個朋友時,他要么打個招呼! 或喲!

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);

使用靜態綁定,您可以在編譯時知道調用哪個方法。 使用動態綁定,您將無法做到,只知道合適的綁定就可以了。 這是子類型多態性的關鍵點。

通常,將靜態綁定和動態綁定混合用於方法時要小心。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM