class C
{
public:
C() : m_x(0) { }
virtual ~C() { }
public:
static ptrdiff_t member_offset(const C &c)
{
const char *p = reinterpret_cast<const char*>(&c);
const char *q = reinterpret_cast<const char*>(&c.m_x);
return q - p;
}
private:
int m_x;
};
int main(void)
{
C c;
std::cout << ((C::member_offset(c) == 0) ? 0 : 1);
std::cout << std::endl;
std::system("pause");
return 0;
}
上面的程序输出1
。它的作用是检查c
对象和c
的字段m_x
的地址。它打印出1
,这意味着地址不相等。我的猜测是因为d'tor是虚拟的,因此编译器必须为类创建vtable
并在类的对象中放置vpointer
。如果我已经错了,请纠正我。
显然,它将vpointer
放在对象的开头,将m_x
字段推得更远,从而给它一个不同的地址。是这样的吗?如果是,那么标准是否指定vpointer
在对象中的位置?根据{{3}},它依赖于实现。它的位置可能会改变程序的输出。
您是否可以在未指定目标平台的情况下始终预测此程序的输出?
答案 0 :(得分:2)
实际上,它几乎总是以这种方式布局。但是,C ++标准允许使用任何工作。而且我可以想象几个不能满足上述要求的解决方案 - 尽管它们可能不适合作为真正的解决方案。
但是请注意,如果您有多个继承,则可以为对象提供多个vptr / vtable。
答案 1 :(得分:1)
C ++中没有“vpointers”。多态和动态调度的实现由编译器决定,并且不会以任何方式指定生成的类布局。当然,多态类型的对象必须携带某些额外状态,以便在仅给出基础子对象的视图时识别具体类型。
使用vtable和vptrs的实现是常见且流行的,并且将vptr放在类的开头意味着您不需要对单继承向上和向下转换进行任何指针调整。
许多C ++编译器都遵循Itanium ABI for C++的(部分),它指定了类似的类布局决策。此popular article也可能提供一些见解。
答案 2 :(得分:1)
是的,它是依赖于实现的,不,你不能在不知道目标平台/编译器的情况下预测程序的输出。