從編譯器角度理解虛函式和繼承

2021-06-03 11:50:03 字數 1284 閱讀 7009

在c++中,繼承的概念可以理解為c中得巢狀結構體,對於各種函式,類中的成員函式,類中的友元函式,各種繼承的虛函式,只要從編譯器的角度去理解

就會變得簡單。例如下例:

class d;

class d1 : public d;

class d2 : public d1;

函式的具體實現略

int main(int argc, char **argv)

在主函式中,只有乙個物件例項,即class d2型別的dd2;d2類直接繼承自d1,間接繼承自d,因為可以用這兩種型別的指標引用d2型別的物件例項。

從編譯器角度來看時,對於①處,編譯器將做如下處理:

1.判斷指標型別,發現d_ptr的型別是class d。

2. 在class d中尋找 v_func_d函式的定義,如果沒有定義,將報錯。

3. 如果有乙個定義,判斷是不是虛函式。

3.1 如果不是虛函式(正如本例那樣),則在全域性符號表中找到相應的修飾後符號,假設為v_func_dd_classd_void,並根據符號對應的函式位址呼叫該函式。

3.2 如果在class d中v_func_dd被定義為虛函式,則需要動態繫結。

於是,在①處,由於v_func_dd並沒有在class d中被定義為虛函式,則編譯器將判斷該呼叫為int d::v_func_dd(),這裡與呼叫乙個全域性函式並無區別。

對於②處的函式呼叫,編譯器將會做出相同處理:

1.判斷指標型別,發現d1_ptr的型別是class d1。

2. 在class d1中尋找 v_func_d函式的定義,如果沒有定義,將報錯。

3. 如果有乙個定義,判斷是不是虛函式。

3.1 如果不是虛函式,則在全域性符號表中找到相應的修飾後符號,此時為虛函式,跳過此步。

3.2 在class d1中v_func_dd被定義為虛函式,則需要動態繫結,在動態繫結時,由於d1_ptr繫結的物件是d2型別,而此時d2型別的虛函式表已經建立好,並填入了

int d2::v_func_dd()的位址,所以這裡呼叫的真正函式是int d2::v_func_dd()。

對於③處的處理,編譯器判斷指標型別d1_ptr為class d1,而d1中並沒有func_d2的定義,即是d1_ptr繫結的是d2物件,編譯器也是不允許這種情況的,所以編譯器將報

未定義的錯誤。

對於④的處理,由於指標是class d2型別,因此會正確呼叫int d2::func_d2()函式,這是,呼叫該成員函式和呼叫乙個全域性函式的情況並無區別,只不過編譯器根據型別名,

引數名,和函式名對最後生成的全域性符號進行了mangling。

從編譯器角度看 lambda表示式

lambda轉換為函式物件。現在,android已經全面轉向c 11 14標準了,看 的話,很多地方變化很大,新標準真的是有點顛覆性的,感覺已經不會c 了。今天有看到lambda表示式,突然想看一下,這貨是怎麼實現的,如下,寫了個例子,分別呼叫3個lambda表示式 include include ...

編譯器角度看C 複製建構函式

關於複製建構函式的簡單介紹,可以看我以前寫過的一篇文章 複製控制之複製建構函式該文章中介紹了複製建構函式的定義 呼叫時機 也對編譯器合成的複製建構函式行為做了簡單說明。本文因需要會涉及到上文的一些知識點,但還是推薦先閱讀上文。本文主要從編譯器角度對複製建構函式進行分析,糾正以前對複製建構函式的一些錯...

從編譯器角度分析C語言中陣列名和指標的區別

陣列名和指標是兩個往往很容易讓人們混淆的概念,很多人以為陣列名就是乙個指標,也有很多人知道陣列名不同於指標但是僅知道陣列名的值不能像指標一樣改變。例如你可以寫出下面這樣的 int p p 卻不能寫這樣的 int a a 那麼陣列名跟指標之間到底有什麼區別呢?第一,在宣告上,只有作為函式引數的陣列名編...