英特尔 C++ 编译器将 vptr(指向虚函数表的指针)存储在对象中的什么位置?
我相信 MSVC 把它放在对象的开头, gcc 放在最后。icpc(英特尔 C++ 编译器)是什么?
您始终可以查看此地址和派生类中的第一个地址所在的位置:
#include <stdio.h>
class foo
{
public:
virtual int do_foo()=0;
};
class bar : public foo
{
public:
int bar;
int do_foo() {printf ("%08x %08x\n", this, &bar);}
};
int main()
{
bar a_bar;
a_bar.do_foo();
}
在我的 linux 机器上,结果是:
bfdbef3c bfdbef40
...这正是您所期望的:第一个指针加上虚函数指针的大小就是第二个指针的位置。
对于 Intel C++ 编译器,对于 Linux,我发现它是对象的开头。
代码:
#include <cstdio>
class A
{
int a, b;
public:
A(int a1, int b1): a(a1), b(b1) {}
virtual void p(void) { printf("A\n"); }
};
class B: public A
{
public:
B(int a1, int b1): A(a1, b1) {}
void p(void){ printf("B\n"); }
};
int main(void)
{
A a(1, 2); int p=10; A a1(5, 6);
B b(3, 4); int q=11; B b2(7, 8);
a.p();
b.p();
int * x=(int*)&a;
printf("%d %d %d %d\n", x[0], x[1], x[2], x[3]);
x=(int*)&b;
printf("%d %d %d %d\n", x[0], x[1], x[2], x[3]);
}
你是什么意思“在函数的开头”?无论如何,Windows 编译器将 vptr 放在对象的偏移量 0 处,而 Unix 编译器将它放在最后一个成员数据之后。英特尔为 Windows 和 Unix 生产编译器,我希望 Win 版本将 vptr 放在开头,将 *nix 版本放在对象的末尾。
vtable 指针在对象中的位置与操作系统无关。这只是编译器和其他工具的约定。
Sid Datta,您可以从 ICC 反汇编某些编译模块中发现该信息。
除了满足您的好奇心之外,您问题的真正答案不会很有用,因为 C++ 标准没有定义这样的细节。因此,任何编译器供应商都可以按照他们认为合适的方式实现这些功能。这也是 C++ 没有跨平台 ABI(应用程序二进制接口)的原因之一。