2016-01-05 50 views
0

這是問我在採訪一個問題...構造器分配後更改vtable內存?

Is it possible to change the vtable memory locations after it's 
created via constructor? If yes, is it a good idea? And how to do that? 
If not, why not? 

,因爲我不有深入的想法對C++的,我的猜測是,這是不可能的它的創建後改變虛表!

任何人都可以解釋一下嗎?

+0

簡單的答案:是的。是。它是自動的。這被回答,你的答案是什麼? –

回答

1

C++標準並沒有告訴我們如何實現動態分派。但是vtable是最常見的方式。

通常,對象的前8個字節用於存儲指向vtable的指針,但只有當對象至少有1個虛函數時(否則我們可以將這8個字節保存爲其他內容)。並且在運行時不可能更改vtable中的記錄。

但你有memset或memcpy像函數,可以做任何你想做的(改變vtable指針)。

代碼示例:

#include <bits/stdc++.h> 

class A { 
    public: 
    virtual void f() { 
     std::cout << "A::f()" << std::endl; 
    } 
    virtual void g() { 
     std::cout << "A::g()" << std::endl; 
    } 
}; 

class B { 
    public: 
    virtual void f() { 
     std::cout << "B::f()" << std::endl; 
    } 
    virtual void g() { 
     std::cout << "B::g()" << std::endl; 
    } 
}; 

int main() { 
    std::ios_base::sync_with_stdio(false); 
    std::cin.tie(nullptr); 
    A * p_a = new A(); 
    B * p_b = new B(); 
    p_a->f(); 
    p_a->g(); 
    p_b->f(); 
    p_b->g(); 
    size_t * vptr_a = reinterpret_cast<size_t *>(p_a); 
    size_t * vptr_b = reinterpret_cast<size_t *>(p_b); 
    std::swap(*vptr_a, *vptr_b); 
    p_a->f(); 
    p_a->g(); 
    p_b->f(); 
    p_b->g(); 
    return 0; 
} 

輸出:

A::f() 
A::g() 
B::f() 
B::g() 
B::f() 
B::g() 
A::f() 
A::g() 

https://ideone.com/CEkkmN

當然,所有這些操作的是拍攝自己的腳的方式。

+1

「前8個字節」取決於指針的大小,所以它也可以是1個字節或4個字節。這也不僅僅是內存可以保存的東西,但它必須被用來存儲第一個成員,以便與C結構佈局兼容。 –

+0

@SashaMN我接受了你的回答。你的代碼示例基本上是交換2個指針,而不是直接在vtable中改變任何東西,對吧?所以真正的答案是,不可能操縱實際的vtable條目? –

+0

如果您認爲面試問題提出了這個問題,我擔心您錯了,因爲那樣,它已經假設vtable是在構造函數中創建的,這是無效的假設。我相信這是關於vtable指針(這是許多實現中的實現細節)是否可以改變。 –

1

對這個問題的正確回答很簡單:這個問題不能回答。這個問題討論「vtable內存位置」,然後繼續「在通過構造函數創建它之後」。這句話沒有意義,因爲「位置」是複數,而「它」只能指單數。

現在,如果有一個關於使用vtable指針的典型C++實現的問題,請隨時詢問。我還會考慮閱讀The Design and Evolution of C++,其中包含一些爲了解C++如何工作以及爲什麼需要理解的人的背景信息。