这是我的测试示例:
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,那么它可以工作。
答案 0 :(得分:11)
即使b
此处动态类型为derived
,您也必须使用dynamic_cast
。这是dynamic_cast
的用途,用于在运行时将基类的指针动态转换为派生类。
reinterpret_cast
获取原始指针并将其视为派生类型。但是,由于virtual
继承,必须对指针进行微调,以指向正确的方法调度表,这正是dynamic_cast
将要执行的操作。
答案 1 :(得分:1)
不要reinterpret_cast
它,它会导致多重或虚拟继承的麻烦,就像你的情况一样。简单的static_cast
不会在这里完成工作吗?
要知道原因,请搜索虚拟继承的实现。常见的一种方法是在对象中存储指向基类的指针,因此虚拟基本不会与其派生类共享相同的地址。使用多重继承时有类似的情况。
简而言之,reinterpret_cast
除了将指针转换为int和back(如果int中有足够的大小来包含指针)之外,还做不了多少。
答案 2 :(得分:0)
正如此处建议的其他答案一样,您不能以这种方式使用reinterpret_cast
,因为指针的值base
实际上与的值不同指针到derived
。有效指针是在运行时推导出来的,这就是你必须使用dynamic_cast
的原因。 static_cast
无法工作,因为您在设计时不知道哪个中间类型最派生的类(您要转换为的类)是从您拥有指针的类型派生的
这里真正的问题应该是:我在设计时知道如何从derived
指针计算base
指针。如何避免运行时惩罚(dynamic_cast
)?
坦率地说,我在这里看不到一个非常好的选项,但可能的选项是将指针存储在根类内的常量指针中的派生类型中,如下所示: / p>
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
的{{1}}成员)void*
指针放入derived
。