假设我们有这样的代码:
struct Granny {
int g;
};
struct Mom : virtual Granny {
int m;
};
struct Son : Mom {
int s;
};
int main() {
int x;
std::cin >> x;
Mom* mom = (x ? new Son : new Mom);
Granny* granny = static_cast<Granny*>(mom);
}
类不是多态的,所以 Granny 没有 vtable。现在,根据x,mom指针下可以有不同的内存布局。因此,子对象 Granny 将从对象开始移动 16 或 12 个字节。
问题:是 static_cast 而不是“简单地移动指针”编译在“在 mom 对象中取消引用 vptr(vtable),然后查看某个索引以找到虚拟偏移量,然后最后按此偏移量移动指针”?那么,static_cast 会有 2 个额外的运行时操作吗?如果没有,请解释一下发生了什么。
您可以将这两种情况放入编译器资源管理器中:
Granny* from_Son(Son* x) { return static_cast<Granny *>(x); }
Granny* from_Mom(Mom* x) { return static_cast<Granny *>(x); }
编译为以下三个指令(带有错误检查):
mov rax, QWORD PTR [rdi]
add rdi, QWORD PTR [rax-24]
mov rax, rdi
在此片段中,
rdi
是x
。 [rdi]
是您的 vtable,因此 Granny
的偏移量存储在 vtable 之前的 24 个字节处。