C++之虚函数是如何实现的
最近面試過程中問到了虛函數的實現,當時答對了一部分,現在做一個詳細的分析:
1.什么是虛函數
在某基類中聲明為 virtual 并在一個或多個派生類中被重新定 義的成員函數,用法格式為:virtual 函數返回類型 函數名(參數表) {函數體};,實現多態性,通過指向派生類的基類指針或引用,訪問派生類中同名覆蓋成員函數
2.實現多肽的條件
簡單的說就是:基類的指針或引用指向子類對象,當子類中成員函數和基類成員函數:函數名相同,參數列表相同,返回值相同,并且基類該函數為虛函數時,基類指針調用該函數時是調用的子類的該函數。
3.虛函數表
對C++?了解的人都應該知道虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的。簡稱為V-Table。在這個表中,主是要一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函數。這樣,在有虛函數的類的實例中這個表被分配在了這個實例的內存中,所以,當我們用父類的指針來操作一個子類的時候,這張虛函數表就顯得由為重要了,它就像一個地圖一樣,指明了實際所應該調用的函數。
這里我們著重看一下這張虛函數表。C++的編譯器應該是保證虛函數表的指針存在于對象實例中最前面的位置(這是為了保證取到虛函數表的有最高的性能——如果有多層繼承或是多重繼承的情況下)。?這意味著我們通過對象實例的地址得到這張虛函數表,然后就可以遍歷其中函數指針,并調用相應的函數。
?
覆蓋父類的虛函數是很顯然的事情,不然,虛函數就變得毫無意義。下面,我們來看一下,如果子類中有虛函數重載了父類的虛函數,會是一個什么樣子?假設,我們有下面這樣的一個繼承關系。
class Base
{
public:
virtual void f(){}
virual void g(){}
virtual void h(){}
}
class Derive : public Base
{
public:
virtual void f(){}
virtual void g1(){}
virtual void h1(){}
}?
?
為了讓大家看到被繼承過后的效果,在這個類的設計中,我只覆蓋了父類的一個函數:f()。那么,對于派生類的實例,其虛函數表會是下面的一個樣子:
Derive::f ?
Base::g
Base::h
Derive::g1
Derive::h1
?
我們從表中可以看到下面幾點,
?
1)覆蓋的f()函數被放到了虛表中原來父類虛函數的位置。
?
2)沒有被覆蓋的函數依舊。
?
這樣,我們就可以看到對于下面這樣的程序,
?
????????????Base *b =?new?Derive();
?
????????????b->f();
?
由b所指的內存中的虛函數表的f()的位置已經被Derive::f()函數地址所取代,于是在實際調用發生時,是Derive::f()被調用了。這就實現了多態。
總結
以上是生活随笔為你收集整理的C++之虚函数是如何实现的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 判断一个单链表中是否存在环
- 下一篇: 年龄、性别2022 cnn算法笔记