虛函數

虛函數的結束結點,標誌了虛函數表的結束。函數

WinXP+VS2003下,這個值是NULL佈局

而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,這個值是若是1表示還有下一個虛函數表,若是值是0,表示是最後一個虛函數表。spa

通常繼承(無虛函數覆蓋)

1)虛函數按照其聲明順序放於表中。.net

2)父類的虛函數在子類的虛函數前面。3d

 

通常繼承(有虛函數覆蓋)

 

 

1)覆蓋的f()函數被放到了虛表中原來父類虛函數的位置。指針

 

2)沒有被覆蓋的函數依舊。xml

 

複雜一些的狀況:blog

 

多重繼承(無虛函數覆蓋)

 

 咱們能夠看到:繼承

1)  每一個父類都有本身的虛表。
2)  子類的成員函數被放到了第一個父類的表中。
3)  內存佈局中,其父類佈局依次按聲明順序排列。
4)  每一個父類的虛表中的f()函數都被overwrite成了子類的f()。這樣作就是爲了解決不一樣的父類類型的指針指向同一個子類實例,而可以調用到實際的函數。

重複繼承

 

咱們能夠看見,最頂端的父類B其成員變量存在於B1和B2中,並被D給繼承下去了。而在D中,其有B1和B2的實例,因而B的成員在D的實例中存在兩份,一份是B1繼承而來的,另外一份是B2繼承而來的。因此,若是咱們使用如下語句,則會產生二義性編譯錯誤:內存

D d;

d.ib = 0;               //二義性錯誤

d.B1::ib = 1;           //正確

d.B2::ib = 2;           //正確

注意,上面例程中的最後兩條語句存取的是兩個變量。雖然咱們消除了二義性的編譯錯誤,但B類在D中仍是有兩個實例,這種繼承形成了數據的重複,咱們叫這種繼承爲重複繼承。重複的基類數據成員可能並非咱們想要的。因此,C++引入了虛基類的概念。
 

鑽石型多重虛擬繼承

上述的「重複繼承」只須要把B1和B2繼承B的語法中加上virtual 關鍵,就成了虛擬繼承

把B這個超類放到了最後

1、經過父類型的指針訪問子類本身的虛函數

咱們知道,子類沒有重載父類的虛函數是一件毫無心義的事情。由於多態也是要基於函數重載的。雖然在上面的圖中咱們能夠看到Base1的虛表中有Derive的虛函數,但咱們根本不可能使用下面的語句來調用子類的自有虛函數:

          Base1 *b1 = new Derive();

            b1->f1();  //編譯出錯

任何妄圖使用父類指針想調用子類中的未覆蓋父類的成員函數的行爲都會被編譯器視爲非法。

2、訪問non-public的虛函數

另外,若是父類的虛函數是private或是protected的,但這些非public的虛函數一樣會存在於虛函數表中,因此,咱們一樣可使用訪問虛函數表的方式來訪問這些non-public的虛函數,這是很容易作到的。

 

咱們能夠經過獲得虛函數指針和偏移的方式取得上述說的兩種狀況。

 

轉載:https://blog.csdn.net/haoel/article/details/3081385

相關文章
相關標籤/搜索