做專案的過程中,碰到乙個問題。
問題可以抽象為下面的問題:
普通人吃飯拿筷子,小孩吃飯拿勺子。
classpeople
virtual
void
get_util_to_eat()
};class children : public
people
};int
main()
輸出結果:
children get scoop
當然這也符合我們的預期。
因為people不是虛函式,所以上述程式呼叫的是people中的eat方法,這就涉及到乙個之前我一直模糊的概念,在乙個類方法中呼叫虛方法,是如何呼叫的。
這又涉及到之前不得不說的乙個問題:
classa };
intmain()
上述**會輸出什麼,按照直觀的感覺null怎麼可能呼叫方法呢,要出core吧。
但是事實上,輸出的是:
i am a
呼叫類函式的時候,c++編譯器並不會管該類是否為空,而是將該類的位址當做this指標傳到函式中去。
a->print() 時,在編譯器中就相當於print(a)
有因為print中沒有用到成員變數的情況,所以自然能很正確的執行。
然後來看下彙編**就能更理解了。以下是people類內的彙編**。
21void
eat() {
0x0000000000400bd2
<+0>: push %rbp
0x0000000000400bd3
<+1>: mov %rsp,%rbp
0x0000000000400bd6
<+4>: sub $0x10,%rsp
0x0000000000400bda
<+8>: mov %rdi,-0x8(%rbp) //rsp表示第乙個引數,也就是類的指標
get_util_to_eat();0x0000000000400be9
<+23>: mov -0x8(%rbp),%rax //將類指標放入rax暫存器中
0x0000000000400bed
<+27>: mov (%rax),%rax //取首位址值,也就是虛表位址
0x0000000000400bf0
<+30>: mov -0x8(%rbp),%rdi //放入rdi中,下次函式呼叫的時候取參用
0x0000000000400bf4
<+34>: mov (%rax),%rax //取出虛表中函式的位址
0x0000000000400bf7
<+37>: callq *%rax //呼叫改函式
總結就是,進入類的非靜態成員函式時,會預設攜帶類的指標(this),然後改函式內用到成員變數、成員方法都等同於在前面加了乙個this->
so 回到最初的那個問題,在people::eat中傳入的是chilren的指標,所以呼叫 get_util_to_eat 時從虛表中取出了children::get_util_to_eat方法並進行呼叫。
手撕虛函式,虛函式呼叫虛函式
乙個類的記憶體分布,虛函式表指標,普通成員變數,sizeof a 為乙個虛表指標 32位是4位元組 普通成員變數 靜態什麼的都不是 虛函式本身也是函式,相當於乙個指標,虛函式表裡面含有虛函式,相當於乙個二級指標,虛函式表指標指向虛函式表,相當於乙個 指標,所有可以通過乙個 指標直接訪問某個虛函式。見...
C 建構函式中呼叫虛函式
我們知道 c 中的多型使得可以根據物件的真實型別 動態型別 呼叫不同的虛函式。這種呼叫都是物件已經構建完成的情況。那如果在建構函式中呼叫虛函式,會怎麼樣呢?有這麼一段 class a virtual void func void test public int m ival class b publ...
C 建構函式中呼叫虛函式
談談關於建構函式中呼叫虛函式的情況,僅討論單繼承,不考慮虛擬繼承和多重繼承。測試平台 vs2013 win7x64 乙個例子 include include class base public virtual void func class deri public base public virtu...