日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++?多態虛函數的底層原理深入理解_C 語言

作者:煉丹之路??????? ? 更新時間: 2022-09-30 編程語言

1?多態的基本概念

1.1 什么是多態?

  • 多態是在不同繼承關系的類對象,去調用同一函數,產生了不同的行為,通常是父類調用子類的重寫函數,在C++中就是 父類指針指向子類對象,此時父類指針的向下引用就可以實現多態

比如看下面的代碼:

class Animal
{
public:
  //虛函數
  virtual void speak()
  {
    cout << "動物在說話" << endl;
  }

  virtual void eat(int a )
  {
    cout << "動物在吃飯" << endl;
  }
};

class Cat :public Animal
{
public:
  void speak()
  {
    cout << "小貓在說話" << endl;
  }

  void eat(int a)
  {
    cout << "小貓在吃飯" << endl;
  }
};
class Dog :public Animal
{
public:
  void speak()
  {
    cout << "小狗在說話" << endl;
  }
};

這兩個類實現集成關系,簡單來說就是 Animal是父類,Cat是子類,通過父類引用調用子類函數,這就是多態(字面意思就是一個對象多個狀態),這樣就 符合** 高內聚低耦合** 的設計原則,更容易 后期維護與修改

1.2 怎么實現多態

說了這么多,那么多態到底怎么實現呢?

  • 想必上面代碼中也已經透露出了一些信息,并且十分關鍵。沒錯,就是virtual,字面意思是 虛擬的,而也的確如此,這個關鍵字修飾的 函數,叫做虛函數,擁有虛函數的 類,被稱為?抽象類(虛類),virtual是實現多態的必要不充分條件
  • 同時 ,子類要重寫父類的虛函數,什么叫重寫?就是函數類型,函數名,參數列表完全相同。
  • 并且父類指針還要指向子類對象,

正如下所示:

void doSpeak(Animal & animal) //Animal & animal = cat;
{
  animal.speak();
}

void test01()
{
  Cat cat;
  doSpeak(cat);

  Dog dog;
  doSpeak(dog);
}

如此方能滿足實現多態的三個條件:

  • 注:如果沒有多態,那么父類指向子類時就無法調用子類函數,也就是此時該函數地址早就綁定好了,只能是animal說話,屬于靜態聯編(靜態);如果想調用小貓說話,這個時候函數的地址就不能早就綁定好,而是在運行階段再去綁定函數地址,屬于地址晚綁定,叫動態聯編,(動態)多態的實現就是依靠動態聯編。

2 虛函數的底層原理

那么虛函數到底是怎么工作的呢?

void test02()
{
  Animal * animal = new Cat;
  ((void(*)()) (*(int *)*(int *)animal)) ();
  typedef void( __stdcall *FUNPOINT)(int);
  (FUNPOINT (*((int*)*(int*)animal + 1)))(10);
}
  Animal * animal = new Cat;

就是animal->speak();

  ((void(*)()) (*(int *)*(int *)animal)) ();

這里?*(int *)animal?解引用到虛函數表中,先將animal類型的指針強轉為int *,然后解引用得到int類型的值放到虛函數表中,然后偏移相應位置指向speak()

 ((void(*)()) (*(int *)*(int *)animal)) ();

調用貓說話,因為C/C++默認調用慣例?__cdecl,而用下列調用時 是__stdcall

typedef void( __stdcall *FUNPOINT)(int);
(FUNPOINT (*((int*)*(int*)animal + 1)))(10);

原文鏈接:https://juejin.cn/post/7127677550599340046

欄目分類
最近更新