指向base的指针<=指向派生类的指针?

Lor*_*one 10 c++ inheritance casting

我想知道C++标准是否保证单个继承使对象"向上"增长,即给定a class Base和a class Derived: public Base,以及指针Derived* ptr,结果dynamic_cast<Base*>(ptr)总是在数值上小于或等于ptr.

Bra*_*vic 9

不.内存布局是实现细节.

话虽如此,假设没有虚函数,我不知道任何实际上没有这样做的实现.如果你引入了一个虚函数Derived(但是没有Base),虚拟表指针可以(取决于实现)放在Base字段之前(使得Base*大于Derived*).

澄清:

上面的示例是Visual C++特定的.您可以使用以下代码进行检查:

class Base {
    int X;
};

class Derived : public Base {
    virtual void f() {
    }
    int Y;
};

int main() {

    Derived d;
    Derived* d_ptr = &d;
    Base* b_ptr = dynamic_cast<Base*>(d_ptr); // static_cast would be enough BTW.

    bool base_smaller_or_equal = (ptrdiff_t)b_ptr <= (ptrdiff_t)d_ptr;

    return 0;

}
Run Code Online (Sandbox Code Playgroud)

base_smaller_or_equal会是false在Visual C++.根据@ enobayram的评论,它应该true在GCC之下.

无论如何,这是一个实现细节,不能依赖.

  • @enobayram:不,在这种情况下,v指针将是第一个字段.这实际上不仅适用于gcc,而且适用于Itanium ABI.你可以很容易地演示它. (2认同)

Mat*_* M. 7

没有.

但是,没有必要恐慌.虽然标准C++中没有完全解决这类问题,但编译器将遵循ABI文档.许多编译器,如gcc,Clang或icc(但不是 VC++)都遵循Itanium ABI.

在Itanium ABI中,只要您具有单个非虚拟继承且Base类具有虚方法,则Derived和Base将始终具有相同的地址.

话虽这么说,这是一个你实际上不用担心的实现.您可以完美地编写符合C++标准的代码,并仍然可以管理您的用例.问题是,C++允许你施放任何指针void*char*(后者为一个特定的例外非混叠)和背部.你需要担心的唯一一件事就是,当你把a转换Base*为a时,void*你需要把它归还给a Base*而不是a Derived*.也就是说,您输入的类型和您获得的类型应匹配.

然而,要知道(确定)物体的大小要困难得多.这需要应用于sizeof当前动态类型的对象,并且无法获得它virtually.

我的建议是实际检测你的基类:

class Base {
public:
  char const* address() const { return (char const*)dynamic_cast<void const*>(this); }
  size_t offset() const { return this->address() - (char const*)this; }

  virtual size_t size() const { return sizeof(Base); } // to be overriden

  virtual ~Base() {}
};
Run Code Online (Sandbox Code Playgroud)

这有助于获取所需的所有信息(请参阅演示).请注意,使用Itanium ABI offset()将始终返回0,但至少您不会在这里假设.