這是問我在採訪一個問題...構造器分配後更改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++的,我的猜測是,這是不可能的它的創建後改變虛表!
任何人都可以解釋一下嗎?
這是問我在採訪一個問題...構造器分配後更改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++的,我的猜測是,這是不可能的它的創建後改變虛表!
任何人都可以解釋一下嗎?
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()
當然,所有這些操作的是拍攝自己的腳的方式。
「前8個字節」取決於指針的大小,所以它也可以是1個字節或4個字節。這也不僅僅是內存可以保存的東西,但它必須被用來存儲第一個成員,以便與C結構佈局兼容。 –
@SashaMN我接受了你的回答。你的代碼示例基本上是交換2個指針,而不是直接在vtable中改變任何東西,對吧?所以真正的答案是,不可能操縱實際的vtable條目? –
如果您認爲面試問題提出了這個問題,我擔心您錯了,因爲那樣,它已經假設vtable是在構造函數中創建的,這是無效的假設。我相信這是關於vtable指針(這是許多實現中的實現細節)是否可以改變。 –
對這個問題的正確回答很簡單:這個問題不能回答。這個問題討論「vtable內存位置」,然後繼續「在通過構造函數創建它之後」。這句話沒有意義,因爲「位置」是複數,而「它」只能指單數。
現在,如果你有一個關於使用vtable指針的典型C++實現的問題,請隨時詢問。我還會考慮閱讀The Design and Evolution of C++,其中包含一些爲了解C++如何工作以及爲什麼需要理解的人的背景信息。
簡單的答案:是的。是。它是自動的。這被回答,你的答案是什麼? –