向下转型非多态类型?

3
请看下面的 C++20 程序:
struct B { B(); private: int whatever; }; // non-aggregate
struct D : B { D(); int x; private: int whatever2; }; // non-aggregate

int main() {
   D* d = new D;
   d->x = 42;
   B* b = (B*) d;
   D* d2 = (D*) b;
   return d2->x;
}

这个程序是否不规范或存在未定义行为?

也就是说,将非多态类型的派生对象的基类子对象的指针转换成指向派生对象本身的指针是允许的吗?

如果允许,那么 *_cast<T> 函数中的哪一个比 C 风格的转换更合适?

(此外,如果指针指向的是不是类型为 D 的对象的基类子对象,则它是未定义的行为,对吗?实现无法像使用 dynamic_cast 那样检查转换是否正确?)


将D分配给B是可以的,甚至不需要强制类型转换:B* b = d就可以了。 从B转回D,你需要进行强制类型转换。至于哪种转换形式,如果您知道您的B实际上是一个D,则D* d2 = static_cast <D*> (b)是首选的C++方式。 如果您不确定,则D* d2 = dynamic_cast <D*> (b)将按预期进行转换,如果bD*,则它会产生空指针。请注意,dynamic_cast会产生一些运行时成本。 - Perette
@Perette,您不能在非虚拟类型上使用dynamic_cast。但是对于其他部分,您是正确的,static_cast是首选方法。 - Guillaume Racicot
1个回答

4

这个程序是良好的。您可以将指针从基本类型转换为子类型而不会出现任何问题。

如果是这样,使用 *_cast 函数是否比 C 风格的转换更合适?

当然!默认使用的转换是 static_cast<T>(...)。它将避免对不相关类型进行转换,这可能会导致未定义的行为。

例如,C 风格转换将接受您的代码,即使 BD 不相关,但使用 static_cast 的代码将被拒绝


C风格会退回到reinterpret。请注意,有一种情况是C风格会做一些动态和静态不会做的事情,这不是UB,也不是reinterpret。 - Yakk - Adam Nevraumont

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接