虛函式(繼承,多型中的理解,vptr和vtbl)

2021-10-09 02:06:31 字數 2507 閱讀 9616

繼承和虛函式

物件模型:關於vptr和vtbl

侯捷大神的課程(講的巨tm好!有一定難度,但是很精彩,c++學習的小夥伴一定要看!)

我們知道,如果子類繼承了父類,那麼子類是能夠繼承父類的所有資料的(如果繼承限制允許)

繼承中使用虛函式:

不是虛函式:這樣的函式在父類中已經設計好,而且是不想要子類繼承的

不純虛函式:這樣的函式父類已經實現了,子類在繼承父類此函式的時候,能夠根據自己的需求使用或者完善這個功能

純虛函式:所有的功能父類已經實現了,讓子類繼承這個功能(也是能修改的)

虛函式最經典的用法:

很巧妙的框架:

因為有些函式子類沒法實現(或者父類所設計的功能是拿來賣錢,賣給子類),所以就繼承父類,通過子類的物件來呼叫父類的函式 mydoc.onfileopen();

讓子類定義所繼承的父類,完成功能,也就是父類提出了功能,將其延緩了(幾年後再用等),子類在用的時候在去定義它,這個方法就是(template method)

下面舉乙個栗子:    

某廠面試題:

poorcowboy

回答:

typedef void( *fun )( void ); //把fun定義為乙個沒有引數,返回void型別的du函式指標

*( ( int* ) * ( int* )( &b ) + i )這一段,

(int*)*相當於沒有進行zhi任何操作,所以等同於

*( ( int* )( &b ) + i )

這裡先取b的位址dao,然後把位址轉換成int*,之後+i是指標算術,也就是在b的位址上加乙個int的長度,最後最前面的*是解指標,座椅這段最後返回的是「b的位址+i個int長度的值」

最前面的(fun)是強制把「b的位址+i個int長度的值」轉換為乙個「沒有引數,返回void型別的函式指標」,所以pfun就是乙個函式指標,其指向的位置從一開始的b的位址,每次迴圈加乙個int的長度

然後我們開看,b的位址,b是乙個b型別,b型別的第乙個函式是g(),而第一次迴圈pfun的位址就是b的位址,b又沒有屬性(私有或共有變數)所以b的位址就是b中第乙個函式g的位址,所以第一次迴圈的pfun()相當於呼叫b::g

( fun )*( ( int* ) * ( int* )( &b ) + i ); 這裡*( ( int* ) * ( int* )( &b ) + i )最前面的*是對上面的結果進行解指標,也就取把b的位址+i個int長度的這個位址的值,並把它轉換為fun型別,也就是乙個沒有引數,返回void型別的函式指標,所以最後得到的就是乙個函式指標。這個指標所指向的位址就是

然後我們來看迴圈,迴圈中3次pfun變數分別被賦了3次值,每次都是乙個函式指標

由於b型別中有virtual函式,所以b的位址指向的是b的vtbl(如果你不知道這個,你面試就沒戲了),vtbl可以看作乙個儲存了函式指標的陣列,每個元素就是乙個int長度,在vtbl中b::g,a::f,b::h是按照如上順序排列的,所以第一次迴圈指向b::g,那麼後兩次就指向a::f和b::h了

至於為什麼是按照這樣的順序排列的,是因為其宣告順序,首先是父類的virtual函式按照其生命順序放入vtbl中,然後是子類的放進去,所以其順序是:a::h,a::f(這是父類的宣告順序)子類中只有b::h是新宣告的,所以順序是a::g,a::f,b::h。

又因為b的型別是b,你知道什麼事多型和動態繫結,就明白第乙個呼叫的為什麼是b::g而不是a::g了。

haoel

大神的文章:

通過指標p 呼叫c::vfunc1()

編譯器看到乙個呼叫的動作,在過去c的時代,是把它編譯成乙個特定的語法,call呼叫***乙個位址,你要呼叫哪乙個函式,編譯器就跳到乙個地方去,將來在return 回來,這就是靜態繫結,精準到位址。

現在通過指標呼叫虛函式的時候,是物件導向設計的關鍵,避免繁瑣的型別判斷動態繫結(虛機制),邏輯意義就是走的vptr->vtbl->fun()  

(條件:

通過指標呼叫,

指標p需要向上轉型,子類->父類,即new的物件是子類,宣告時是父類,保證安全

必須要有虛函式)

虛函式的指一種用法就是多型,指標指向不同的型別listmylist

解析成c:  (*(p->vptr)[n])(p);

C 繼承中的多型 虛函式 虛析構函式

從c 繼承中的相容原則中我們知道 父類指標可以直接指向子類物件,父類引用可以直接引用子類物件。當父類和子類有相同方法時呼叫的是父類方法,即是根據指標型別或引用型別來確定呼叫的方法型別的。如果我們想根據指標實際指向的物件型別 引用實際引用的型別 來決定呼叫的方法型別,需要把這個函式宣告為虛函式,這就是...

C 多型中的VPTR

以下文字摘錄自 為了完成這件事,編譯器對每個包含虛函式的類建立乙個表 稱為vtable 在vtable中,編譯器旋轉特定類的虛函式位址。在每個帶有虛函式的類中,編譯器 秘密 地置一指標,稱為vpointer 縮寫為vptr 指向這個物件的vtable。通過基類指標 或者引用 做虛函式呼叫時,也就是做...

C 多型中的VPTR

以下文字摘錄自為了完成這件事,編譯器對每個包含虛函式的類建立乙個表 稱為vtable 在vtable中,編譯器旋轉特定類的虛函式位址。在每個帶有虛函式的類中,編譯器 秘密 地置一指標,稱為vpointer 縮寫為vptr 指向這個物件的vtable。通過基類指標 或者引用 做虛函式呼叫時,也就是做多...