c 多型的內幕

2022-05-18 01:08:23 字數 2326 閱讀 8311

既然提到了指標,那就讓我們用記憶體位址來證明一下吧。

為了證明,我們必須要取到成員函式的首位址。利用下面的函式取得成員函式的位址

templatedst_type pointer_cast(src_type src)

呼叫上面函式的方法:

void* p1 = pointer_cast(&類名::成員方法名);
#include "stdio.h"

#include "string.h"

#include templatedst_type pointer_cast(src_type src)

class a

void funca()

};class b:public a

void funcb()

};int main()

實驗環境:gcc version 7.3.0。ubuntu18.04

gdb裡的操作步驟1,先用【info line 22】命令去得到a類的成員函式funca的位址,22是成員函式funca所在的行號。

gdb裡的操作步驟2,因為p1是指向a類的成員函式funca的指標,所以【p p1】的結果就是a類的成員函式funca的位址。

位址偏移量是啥?

當執行程式時,先從硬碟把程式載入到記憶體中,這個程式就成為了乙個執行中的程序,作業系統會給程序分配虛擬記憶體空間,為了能夠呼叫到函式,必須知道函式在的虛擬記憶體空間的位址。這個位址呼叫側怎麼知道的呢,在編譯階段,編譯器自動把被呼叫函式相對於程序首位址的偏移量算出來了,告訴了呼叫測,所以呼叫側才能找到被呼叫函式的位址。

指標p1指向的類a的func成員函式;

指標p2指向的類b的func成員函式;

但是從gdb的結果來看,他們指向的位址都是0x1,也就說明他們沒有正確的指向類的成員函式。

那麼類的成員函式的位址在**呢?看下面的gdb截圖

通過【p x】檢視物件x,發現x裡面多了個_vptr的東西。這個東西就是最開始說的二級指標(指標陣列)。

步驟2:【p *(void**)0x555555755d48】,先把_vptr指標轉成void型的二級指標,然後再用【*】取得位址裡的內容,發現位址類存放的就是類a的成員函式func的位址0x555555554cc4。

問題來了,如何得到第二個呢?因為64位系統指標所佔8個位元組,所以(_vptr + 8)就是第二個虛函式的位址。

當有如下**:用父類的指標指向子類的物件(多型的最終目的:面對抽象類程式設計),然後呼叫子類和父類完全相同的函式(必須是虛函式)。讓人迷惑,到底呼叫的是哪個。

a* m = new b(1,2,3,4);//b是a的子類

m->func();

m->func1();

用父類的指標呼叫虛函式時,先去它指向的記憶體中(子類所占用的記憶體)找_vptr,然後從_vptr裡找函式的位址。非虛函式的位址不在_vptr裡。

步驟1:【p *m】,發現m是類a的物件

步驟2:【set print object on】,含義是顯示物件真正的型別

步驟3:【p *m】,發現m原來不是類a的物件,而是類b的物件。

步驟4:檢視_vptr裡第乙個指標,發現指向的是b的func;加8後得到第二個指標,發現發現指向的是b的func1.

C 多型內幕

既然提到了指標,那就讓我們用記憶體位址來證明一下吧。為了證明,我們必須要取到成員函式的首位址。利用下面的函式取得成員函式的位址 template dst type pointer cast src type src 呼叫上面函式的方法 void p1 pointer cast 類名 成員方法名 in...

C 多型 繼承多型

什麼是多型?個人理解為 在程式語言繼承關係中,子類能替代父類,表現出不同的行為。換句話說 在繼承關係中,乙個類被例項化被其子類替代,子類中有父類的虛方法重寫,或者有父類同名方法 new 呼叫相同方法時候,將表現出子類或者父類中不同行為 老闆,上 static void main string arg...

C 什麼是多型,多型的用途

qq群 807236138 群稱 ios 技術交流學習群 1 定義 乙個介面,多種方法 程式在執行時才決定呼叫的函式。2.實現 c 多型性主要是通過虛函式實現的,虛函式允許子類重寫override 注意和overload的區別,overload是過載,是允許同名函式的表現,這些函式引數列表 型別不同...