先來看一段簡單的**。
這道題也是經常在筆試中會遇到的,很多人可能都不能完全答對,一般只要c++有一定的經驗,大部分都能答對前面兩個函式呼叫,對於剩下兩個可能就不太確定了,雖然感覺不太實用,但這的的確確能體現乙個程式設計師對類繼承的理解深度。
有些人的可能答案是這樣的:
cderived::func1
cbase::func2
cbase::func1
cbase::func2
但結果真是這樣的嗎?
首先我們分析一下上面的結果。
① 函式呼叫pbase->func1()的結果顯然是cderived::func1。會c++的都知道,這是多型的表現,基類的指標指向派生類物件,如果該函式是虛函式,那會呼叫會呼叫當前實際物件的vtable表中對應的函式,也就是cderived::func1。
② 函式呼叫pbase->func2()的結果是cbase::func2。原因在於:如果被呼叫的函式不是虛函式,那麼函式呼叫會根據指標的型別來呼叫,而這裡是基類指標在呼叫,所以最終呼叫的是基類的函式func2() ,輸出為cbase::func2。
對於這句話,cderived* pderived = (cderived*)&base,我原先的想法是,這肯定有問題,怎麼能直接將基類物件的指標強轉成派生類的指標呢,這樣肯定會引起物件的切割。但實際上,這和物件切割一點關係都沒有,如果是(cderived)base,將物件base強轉成cderived的物件,這才叫物件切割。所以,這裡直接進行指標轉化是沒有問題的。不就將指標的型別轉換一下嘛,又沒有改變指標本身的值,所以這裡沒有危險。
③ 對於函式呼叫pderived->func1()來說,因為之前進行了指標的轉換,將基類的物件base的位址賦值給派生類的指標,所以很多人就不確定了,到底是呼叫哪個類的函式呢,是cbase::func1還是cderived::func1,結果往往是連懵帶猜,隨便寫個算了。其實如果再對vtable稍微深想一下的話,可能就知道應該是什麼樣的答案了。
我的想法是,無論是pbase->func1()還是pderived->func1(),它們的做法都是需要先判斷函式fun1是不是虛函式,如果是的話,那會就會去vtable裡面去找,當前物件應該呼叫的那個函式。每個類在宣告乙個或多個物件之後,如果類中有虛函式,那麼就會為每個物件鑲嵌乙個__vfptr的指標,用它來指向vtable表,並且同乙個類的所有物件的__vfptr值和vtable表中的內容都是完全一樣的【但是,我有個疑問,因為同乙個類的所有物件共享乙個__vfptr指標,到底__vfptr能不能看成類的靜態成員?這個估計與編譯器實現有關】。所以,對於pderived->func1()來說,它會去pderived所指向物件的的vtable表中查詢一下fun1這個函式,而pderived所指向物件是base,也就是基類的物件,因此,找到的函式就是cbase::func1,所以,答案是:cbase::func1。
④ 如果能理解②和③的話,對於函式呼叫pderived->func2()來說,答案就已經很明確了,就是cderived::func2了。因為fun2不是虛函式,所以函式呼叫的時候不會去vtable中去找,也就是說,fun2的呼叫不能根據物件的實際型別來找對應的函式,而只能根據呼叫的指標的型別來判斷呼叫的函式。
所以,最終的結果是:
cderived::func1
cbase::func2
cbase::func1
cderived::func2
因為我對編譯原理不怎麼了解,沒學過,有些東西可能還是沒說明白甚至是說錯了,如有問題,謝謝糾正。
一些常見的面試筆試題
問題1 構造和析構函式中的虛函式呼叫 答案 虛函式可以在建構函式和析構函式中呼叫,但虛函式此時是靜態繫結 而非動態繫結。問題2 c 中的異常可不可以是引用 答案 異常可以是引用,並且效率高。問題3 tcp狀態中的close wait是什麼狀態 答案 close wait狀態是被動關閉方的乙個狀態,此...
一些筆試題
int main int argc,char argv int multi int a,int b,int c typedef int func1 int in typedef int func2 int int int 013.請寫出下列 的輸出內容 include stdio.h main 解 ...
記一些筆試題
思路 每乙個元素去與後面的元素去比較,只要相等就退出,說明已經找到第乙個重複的字元了。該字串沒有重複字元 例如 輸入 1,4,3,4,null,undefined,nan,null 輸出 6思路 將每乙個元素全部轉成字串,避免了null和undefined的影響。null undefined為tru...