虛函式 虛繼承 C

2021-08-14 14:52:05 字數 2761 閱讀 4779

關於虛表,我們就要用到乙個關鍵字:virtual,可以修飾函式,也可以修飾類。類的成員函式被virtual修飾之後,就成為了虛函式;修飾類,主要是虛繼承。

在此之前,我們首先要了解乙個概念:物件模型,也就是說,乙個基類形成之後,裡面的成員是怎麼存放的,當派生類繼承基類之後,派生類的成員是怎麼存放的。

我們首先看下面一段**,普通的public繼承:

class base;

class derive:public base

;void test()

當我們調出記憶體,檢視時物件d,並依次給_b,_d賦值,

就可以得到派生類物件d的物件模型:

虛繼承:

繼承中有public,private,protected等繼承方式,虛繼承就是用關鍵字virtual 繼承的方式

class base{

private:

int _b;

public:

void funtest1()

{ cout<

我們在記憶體中,檢視派生類的物件:

發現在派生類的物件的前面4個位元組已經存放了一些資料,這個資料就是偏移量**的位址,我們用這個位址在開啟一塊記憶體視窗,裡面的資料如下:

其中,0x00855800存放的是相對於自己的偏移量,也就是0,而0x00855804裡面存放的是相對於基類的偏移量,此時,我們也給出虛繼承的物件模型:

tip:在虛繼承的前提下,建立派生類物件的時候,編譯器就會在前4個位元組寫入偏移量**的位址,所以:在沒有建構函式的情況的下,編譯器一定給派生類合成乙個建構函式。

虛繼承能夠解決菱形繼承產生的二義性問題,這個等下面虛函式講解完成之後,在做介紹。

虛函式:

我們先來看下面的**:

如上圖:建立物件b之後,物件的位址就是0x00cff788,裡面的前4四個位元組已經存放內容,我們在第二個記憶體視窗開啟,發現位址裡面存放的是也是位址,此時我們在監視視窗檢視base類裡fun函式的位址,和記憶體2裡面的位址相同。

那麼在繼承的關係中,虛函式又有著怎麼樣的儲存呢?

我們先看一段單繼承的**

class b

{public:

virtual void fun1()

{ cout<

我們在建立基類物件和派生類物件之後,使用基類的物件,檢視其虛表中存放的位址,再在監視視窗,檢視對應函式的位址,就可以知道虛表裡面存放的對應的函式是哪乙個。

也就很容易得到函式的物件模型:

派生類的虛表生成:

①現將基類的虛函式拷貝乙份

②如果派生類中對基類中的虛函式進行了重寫,那麼派生類的虛函式將替代相同偏移量位置的基類的虛函式

③如果派生類中新增加自己的新函式,那麼就按照在派生類中宣告的次序,依次存放到虛表中。

但是在多繼承中,虛表就又有一些小的變化,我們先給出多繼承的實現:

其物件模型:

b2::funtest4()

c::funtest5()

b2::funtest6()

總結起來物件c的物件模型如下:

此時派生類的虛表的產生和單繼承的時候產生規則一樣,派生類自己新產生的虛函式,存放在按照繼承順序中的第乙個。

c 虛函式和虛繼承

c 中,多型的實現需要虛函式,而虛函式主要包括兩部分,虛函式指標和虛函式表。基類將自己的一些函式設為虛函式,子類則需要在繼承基類後,重寫或者直接使用從基類的繼承下來的虛函式。基類自己會儲存乙份虛函式表,這個虛函式表含有指向基類虛函式的虛函式指標。當子類繼承基類後,同樣會將基類的虛函式表繼承下來,這樣...

虛函式 虛繼承

include using namespace std class a class b public a class c public b int main 結果是 4,4,4 為什麼?一,在private,protect,public的實際繼承中,派生類和基類擁有相同的虛函式表。但如果是虛繼承,會...

虛函式,虛繼承

1 空類,空類單繼承,空類多繼承的sizeof include using namespace std class base1 class base2 class derived1 public base1 class derived2 public base1,public base2 int m...