2014-10-20 95 views
0
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这意味着地址不相等。我的猜测是,这是因为编译器是虚拟的,所以编译器必须为该类创建一个vtable并将vpointer放入该类的对象中。如果我已经错了,请纠正我。vpointer在对象中的位置

显然,它将vpointer放在对象的开头,将m_x字段推得更远,从而给它一个不同的地址。是这样吗?如果标准指定了vpointer在对象中的位置?根据wiki它是实现相关的。它的位置可能会改变程序的输出。

那么你能否总是预测这个程序的输出而不指定目标平台?

回答

1

在C++中没有“vpointers”。多态性和动态分派的实现留给编译器,并且不会以任何方式指定生成的类布局。当然,只给予基础子对象的视图时,多态类型的对象将不得不携带额外的状态以标识具体类型。

vtables和vptrs的实现很常见并且很流行,并且将vptr放在类的开头意味着您不需要对单个继承向上和向下转换进行任何指针调整。

很多C++编译器都遵循(部分)Itanium ABI for C++,它指定类似这样的类布局决定。这popular article也可能提供一些见解。

1

是的,它依赖于实现,不,不知道目标平台/编译器,无法预测程序的输出。

2

实际上,它几乎总是以这种方式布置的。但是,C++标准允许使用任何作品。我可以想象几种解决方案不需要满足上述要求 - 尽管它们可能不能很好地解决问题。

但是请注意,如果您有多个继承,则可以拥有一个以上的vptr/vtable。