6

这是我的测试示例:

struct base {
    virtual ~base(){}
    int x;
};

struct derived: public virtual base {
    base * clone() {
        return new derived;
    }
    derived(): s("a") {}
    std::string s;
};

int main () {
    derived d;
    base * b = d.clone();
    derived * t = reinterpret_cast<derived*>(b);
    std::cout << t->s << std::endl;
    return 0;
}

它在我打印 s 的行崩溃。由于“b”是指向派生类的指针,所以 reinterpret_cast 应该可以正常工作。我想知道为什么它会崩溃。同时,如果我用 dynamic_cast 替换 reinterpret_cast,那么它就可以工作。

4

3 回答 3

14

就算b是这里动态的类型derived,你也得用dynamic_cast。这就是 dynamic_cast在运行时将基类的指针动态转换为派生类的目的。

reinterpret_cast获取原始指针并将其视为派生类型。但是,由于virtual继承,必须对指针进行轻微调整以指向正确的方法调度表,而这正是我们dynamic_cast要做的。

于 2011-09-13T23:09:52.653 回答
1

不要reinterpret_cast这样,它会导致多重或虚拟继承的麻烦,就像你的情况一样。不会在这里简单地static_cast完成工作吗?

要知道为什么,请搜索虚拟继承的实现。一种常见的方法是在对象中存储指向基类的指针,因此虚拟基类与其派生类不共享相同的地址。使用多重继承时也有类似的情况。

简而言之,reinterpret_cast除了将指针转换为 int 并返回(如果 int 中有足够的大小来包含指针)之外,无能为力。

于 2011-09-13T23:07:40.080 回答
0

正如这里的其他答案所建议的那样,您不能reinterpret_cast以这种方式使用,因为指向的指针的值base实际上与指向的指针的值不同derived。有效指针是在运行时推导出来的,这就是您必须使用dynamic_cast. static_cast 无法工作,因为您在设计时不知道最派生类(您要转换为的类)是通过哪个中间类型从您有指针的类型派生的。

这里真正的问题应该是:我在设计时就知道如何derived从指针计算base指针。如何dynamic_cast避免 (of) 的运行时惩罚?

坦率地说,我在这里没有看到一个很好的选择,但一个可能的选择是将指向最派生类型的指针存储在根类内的常量指针中,如下所示:

struct base {
  void* const self;
  virtual ~base() {}
  protected:
    base(void* self) : self(self) {}
};
struct derived : public virtual base {
  derived() : base(this) {}
}

这是丑陋和危险的,因为它牺牲了性能的类型安全(如果你真的很幸运,你会从中获得轻微的运行时性能)。但是您将能够将reinterpret_cast您的base指针(self类型的成员void*)转换为derived指针。

于 2011-09-13T23:26:44.153 回答