簡體   English   中英

虛擬 function 調用非虛擬 function 反之亦然

[英]Virtual function calling a non-virtual function and vice versa

我有一個class A作為 class 的基礎class B

我在我的虛擬function, xyz()中調用了非虛擬function, abc() ,如下所述。

由於運行時多態性, B:xyz被調用——我理解這一點。

但是,我不明白,為什么后面跟着B:abc而不是A:abc ,因為abc是非虛擬 function。

請注意:我遇到了以下問題: Virtual function calling a non-virtual function 它提到在虛擬 function 中調用abc()等效於this->abc() ,因此是 output。 但是,我不確定我是否理解這部分。

因為,當我做相反的事情(即非虛擬 function 調用虛擬函數)時,會顯示正確的運行時多態性。 那么 this 指針會發生什么?

//Virtual function calling non-virtual 
class A
{
  public:
  void abc()
  {
    cout<<"A:abc"<<endl;
  }

  virtual void xyz()
  {
    cout<<"A:xyz"<<endl;
    abc();
  }
};


class B: public A
{
  public:
  void abc()
  {
    cout<<"B:abc"<<endl;
  }

  void xyz()
  {
    cout<<"B:xyz"<<endl;
    abc();
  }
};

int main() {

  A *obj3 = new B;
  obj3->xyz();\
  return 0;
}
Output
B:xyz
B:abc
//Non-virtual calling virtual function
#include <iostream>
using namespace std;

class A
{
  public:

  void abc()
  {
    cout<<"A:abc"<<endl;
    xyz();
  }

  virtual void xyz()
  {
    cout<<"A:xyz"<<endl;
  }
};

class B: public A
{
  public:

  void abc()
  {
    cout<<"B:abc"<<endl;
    xyz();
  }

  void xyz()
  {
    cout<<"B:xyz"<<endl;
  }
};

int main() {

  A *obj3 = new B;
  obj3->abc(); 
  return 0;
}
Output
A:abc
B:xyz

Calls to your non-virtual abc function are resolved, effectively, at compile time: so, when that is called from within another member function of class B , the class B version of the function is called, and is passed a pointer ( this )到調用它的 object; 同樣,如果從class class A function 中調用,則將使用class A定義。 也就是說,對於編譯器,非虛擬函數與 class 相關聯,而不是與 class 的任何特定實例相關聯。

但是,編譯器對虛擬xyz function 的處理方式不同; 在這種情況下,對 function 的引用或指針被添加到 class 定義中(這通常被添加到所謂的vtable中,盡管細節是特定於實現的); 創建類的任何對象時,它們包括該 function 指針和/或 vtable 的副本。 當編譯器看到調用這樣一個虛擬 function 的代碼時,它會通過適當的 function 指針將其轉換為調用; so, the function 'travels with' the actual object: whether the function is called from the derived class or base class (in your code) is irrelevant – the function called is the one belonging to the object (instance) from which it is invoked .

總而言之:對非虛函數的調用在編譯時被解析,而對虛函數的調用(在概念上)在運行時被解析。

要查看此“vtable”的實際創建,請嘗試編譯並運行以下代碼:

#include <iostream>

class A {
public:
    int i;
    ~A() = default;
    void foo() { std::cout << i << std::endl; }
};

class B {
public:
    int i;
    virtual ~B() = default;
    virtual void foo() { std::cout << i << std::endl; }
};

int main()
{
    std::cout << sizeof(A) << std::endl;
    std::cout << sizeof(B) << std::endl;
    return 0;
}

這兩個類之間的唯一區別是一個具有虛函數而另一個沒有——但這會導致 class 對象的大小存在顯着差異:vtable 的大小(可能帶有一些“填充”以實現最佳對齊數據),(在我的 64 位 Windows 上,使用 MSVC,我得到的大小為 4 和 16。但實際值會因編譯器和平台而異。)

暫無
暫無

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

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