2013-04-17 13 views
4

我寫了這個非常簡單的C++程序,我想知道爲什麼編譯器通過兩個指針解引用來佈置vtable。這裏的C++程序:C++ vtables中的雙重間接

class Foo { 
public: 
    virtual void bar() { 
    } 
}; 

int main(int argc, char *arv[]) { 
    Foo foo; 
    Foo *foo_p(&foo); 
    foo_p->bar(); 
} 

現在,我可以看看編譯器生成的彙編:

$ g++ -ggdb -Wall -O0 -S test.cpp 

下面是有關章節:

.loc 1 9 0 
    leaq -16(%rbp), %rax # put the address of 'foo' in %rax 
    movq %rax, %rdi  # use it as the first argument of the following function 
    call _ZN3FooC1Ev  # call the Foo constructor 
    .loc 1 10 0 
    leaq -16(%rbp), %rax # put the address of 'foo' in %rax 
    movq %rax, -24(%rbp) # create 'foo_p' on the stack 
    .loc 1 11 0 
    movq -24(%rbp), %rax # load 'foo_p' into %rax 
    movq (%rax), %rax  # dereference the pointer, put it in %rax 
          # %rax now holds the hidden pointer in 'foo', which is the vtable pointer 
    movq (%rax), %rdx  # dereference the pointer ::again:: (with an offset of 0), put it in %rdx 
          # %rdx now holds a function pointer from the vtable 
    movq -24(%rbp), %rax # create the 'this' pointer (== foo_p) and put it in %rax 
    movq %rax, %rdi  # use the 'this' pointer as the first argument to the following function 
    call *%rdx   # call Foo::bar (via the vtable) 

爲什麼第二個指針引用是必要?爲什麼對象中隱藏的vtable指針不直接指向vtable?

edit:it :: is ::直接指向vtable。我剛剛困惑着我的指針:-P

+0

+1有沒有愚蠢的問題,如果他們準備像這樣 –

回答

6
movq -24(%rbp), %rax # load 'foo_p' into %rax 
movq (%rax), %rax  # fetch VTABLE 
movq (%rax), %rdx  # fetch function `bar` from VTABLE. 

你會看到它更好,如果你添加一個baz(或kerflunk)功能作爲第二功能類,你會看到第二個取處於8到VTABLE。

你可以看到這個類裏面的結構是這樣的(注意,這是「爲了說明的目的,並非是現實」)

struct VTABLE 
{ 
    void (*bar)(); 
}; 

struct Foo 
{ 
    VTABLE *vtable; 
}; 

的構造富[它存在,即使你的內心還沒有宣佈一個],有一段代碼,做:

this->vtable = &VTABLE_Foo; 

和地方的編譯器做了(再次,用於說明目的,名字肯定是不同的):

VTABLE VTABLE_Foo = { foo::bar }; 

所以叫bar,我們會做:

foo_p->vtable->bar(foo_p); 

什麼編譯器顯示的是:

void (*temp)() = foo_p->vtable->bar; 
temp(foo_p); 

這是幾乎可以肯定使用-O0的結果,如果你使用優化編譯,編譯器會更直接地做到這一點(包括可能意識到它在這種情況下不需要vtable,並且內聯函數不會做任何事情,從而完全消除該調用)。

+0

OHHHH哇這是一個愚蠢的問題 – Litherum

+0

很好理解這是如何工作的,只要你不認爲這是完全如何總是因爲編譯器被允許以「任何實際上給出正確行爲的方式」這樣做。 –

2

將首先將其虛表指針%rax,第二個放功能指針爲%rdx