柚子快報(bào)邀請碼778899分享:C++語法——詳解虛繼承
柚子快報(bào)邀請碼778899分享:C++語法——詳解虛繼承
目錄
一.什么是虛繼承
二.虛繼承原理
三.虛繼承使用注意事項(xiàng)
一.什么是虛繼承
所謂虛繼承(virtual)就是子類中只有一份間接父類的數(shù)據(jù)。該技術(shù)用于解決多繼承中的父類為非虛基類時(shí)出現(xiàn)的數(shù)據(jù)冗余問題,即菱形繼承問題。
小編用一張圖來表述一下:
如果是下圖這種非虛繼承,那么D類中就會(huì)出現(xiàn)兩個(gè) int a,當(dāng)我們用D實(shí)例化對象調(diào)用a時(shí),編譯會(huì)報(bào)錯(cuò),因?yàn)榘l(fā)生了混淆。除非指定類域B或C。當(dāng)然指定A也可以,因?yàn)槟J(rèn)會(huì)從第一個(gè)父類中找。
?此時(shí),D的實(shí)例化對象內(nèi)部結(jié)構(gòu)如下:
而當(dāng)我們使用虛繼承時(shí),結(jié)構(gòu)是下圖這樣,D中只有一份父類A,當(dāng)我們調(diào)用A中數(shù)據(jù)時(shí),并不會(huì)發(fā)生冗余。
?此時(shí),D對象內(nèi)部結(jié)構(gòu)是這樣:
二.虛繼承原理
在上圖中,父類數(shù)據(jù)并不存放在虛繼承的子類中,那么子類怎么找到父類數(shù)據(jù)呢?
——在虛繼承的類中,會(huì)定義一個(gè)虛基表指針vbptr,指向虛基表。
而虛基表中會(huì)存在偏移量,這個(gè)量就是表的地址到父類數(shù)據(jù)地址的距離。
我們可以通過調(diào)試,找到虛基表指針和虛基表:
首先,我們?yōu)槊恳粋€(gè)數(shù)據(jù)賦值,以便觀察:
?之后,調(diào)用監(jiān)視,查看d對象地址和d中a數(shù)據(jù)地址:
?再通過d的地址查看內(nèi)存窗口,看d中內(nèi)存分布:
由此我們可以分析得到對象d及其內(nèi)部父類的內(nèi)存布局:
在這個(gè)我們可能會(huì)有個(gè)疑問,那這B和C中兩個(gè)是什么呢?
?這就是虛基表指針!
再通過內(nèi)存窗口,查看一下虛基表指針指向的地址,根據(jù)我們的了解應(yīng)該就是虛基表,而其中存有偏移量:
?而偏移量,就是虛基表指針地址到父類數(shù)據(jù)地址的距離,這里以b中虛基表為例:
到這里我們就能解釋一個(gè)問題:為什么bptr和cptr能夠找到并不位于自己內(nèi)部的變量a?
因?yàn)閎ptr和cptr都對d進(jìn)行了切片,當(dāng)各自尋找變量a時(shí),會(huì)從自身的虛基表指針中找到虛基表,通過虛基表的偏移量找到變量a的地址,從而找到了變量a。?
畫圖解釋就是這樣:
?
三.虛繼承使用注意事項(xiàng)
當(dāng)使用虛繼承的時(shí)候,需要注意,虛繼承只有在多繼承時(shí)才有用。也就是說如果只有一層繼承關(guān)系或者是單繼承都將不起作用。
因?yàn)樘摾^承是保證子類中只有一個(gè)間接父類,說簡單一點(diǎn)就是虛繼承只能在隔代繼承中起作用。
比如下面兩種情況即便虛繼承也沒有意義:
(1)是因?yàn)殡m然虛繼承產(chǎn)生了虛基表和指針,但是class B并沒有子類,而虛繼承是用以保證子類只有一個(gè)間接父類class A。當(dāng)然話說回來,就算有子類、哪怕多個(gè)子類,也都體現(xiàn)不出虛繼承,因?yàn)樘摾^承要求同一個(gè)子類的多個(gè)父類繼承自同一個(gè)間接父類,而該例只有一個(gè)父類class B。
(2)是因?yàn)殡m然class C虛繼承了class B,但是class B是class A的非虛繼承,那么B中就會(huì)有一份A。而class D對A是虛繼承,就導(dǎo)致E在實(shí)例化時(shí)會(huì)存放一個(gè)對D而言公共的A。這樣E中還是存放了兩個(gè)A。調(diào)用變量時(shí)還是會(huì)混淆。
這樣說可能還有些難懂,那換個(gè)說法,class B中沒有虛基表指針,而D中有虛基表指針,當(dāng)E從D調(diào)用int a時(shí)會(huì)從虛基表指針找到公共區(qū)域的A,而E從B中找只會(huì)在B的區(qū)域內(nèi)找到int a。
畫圖表示E內(nèi)部結(jié)構(gòu)就是這樣:
?正確的繼承關(guān)系應(yīng)該是當(dāng)class A的子類繼承時(shí),都是虛繼承,這才能保證當(dāng)有像class E這樣的間接子類定義時(shí),class在其中都只會(huì)在公共區(qū)域有一份。對本例來說即class B是虛繼承。
?
?
只有兩種編程語言:一種是天天挨罵的,另一種是沒人用的——Bjarne Stroustrup(C++之父)
如有錯(cuò)誤,敬請斧正
?
柚子快報(bào)邀請碼778899分享:C++語法——詳解虛繼承
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。