这是未定义的下转换吗

Is this downcasting undefined?

本文关键字:转换 未定义      更新时间:2023-10-16

考虑这个例子,基类有一些数据成员,而派生类只提供了一个额外的方法:

struct TestBase
{
    int x;
    TestBase() : x(5) {}
};
struct TestDerived : public TestBase
{
    void myMethod()
    {
        x=8;
    }
};
int main()
{
    TestBase b;
    TestDerived& d=static_cast<TestDerived&>(b);
    d.myMethod();
}

这是向下转换到错误的类型,所以AFAIU有未定义的行为。但是,在这种情况下,派生类的布局与基类的布局相同,可能会有一些例外吗?

来自标准(强调矿):

§5.2.9静态铸造[expr.Static.cast]…

(2) 类型为"cv1B"的左值,其中B是类类型,可以强制转换为类型"reference to cv2 D",其中D是从B派生的类,如果存在从"指针到D"到"指针到B"的标准转换,cv2为与cv1和B相同或更高的cv资格既不是D的虚拟基类,也不是虚拟基类的基类D的类。结果的类型为"cv2 D"。类型为"cv1 B"的xvalue可能为强制转换为类型"对cv2D的右值引用",具有与类型为"cv1B"的左值如果类型为"cv1 B"的对象实际上是类型D,则结果是指类型D的封闭对象。否则,行为未定义

我的第一个猜测是,在这种情况下,演员阵容应该是有效的,因为我被子对象这个术语弄糊涂了。

现在(多亏了@T.C.和@M.M),很明显,在这种情况下,行为是未定义的

在以下示例中,强制转换是有效的:

int main()
{
    TestDerived d;
    TestBase &br = d; // reference to a subobject of d
    TestDerived &dr = static_cast<TestDerived&>(br);  // reference to the original d object
    d.myMethod();
}

这里,类TestDerivedd)的对象将具有类TestBase的子对象(br是对该对象的引用)。

如果尝试在不兼容的类型之间进行强制转换,则

static_cast<>将生成编译器错误,但它不能保证在编译时或运行时强制转换有效。

由于TestDerived继承自TestBase,因此它是static_cast运算符允许的合法强制转换,但并非所有向下转换都必须是安全的强制转换。

在上面的代码中,它只是碰巧安全地工作——很可能是因为TestMethod只访问基类成员,是单一继承,没有vtables,并且不做任何复杂的事情。因此,编译器很可能将强制转换视为一个无操作的简单示例。其他人会告诉你"这是未定义的行为"——不要对这样写的代码抱有任何假设。(它们也是正确的。)