这种向下倾斜是不确定的?

时间:2015-11-08 18:11:51

标签: c++ undefined-behavior downcast

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

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它有未定义的行为。但是,对于这样的情况,可能存在一些例外情况,即派生类&#39;布局与基类相同?

2 个答案:

答案 0 :(得分:8)

从标准(强调我的):

  

§5.2.9静态演员[expr.static.cast] ......

     

(2)类型为“cv1 B”的左值,其中B是类类型,   可以强制转换为“引用cv2 D”,在哪里    D是从B 派生的类,如果有效   存在从“指针D”到“指针B”的标准转换,cv2是   与cv1和B相同的cv资格,或更高的cv资格   既不是D的虚基类,也不是虚基的基类   D类。结果类型为“cv2 D”。类型为“cv1 B”的x值可以是   使用相同的约束来强制转换为“对cv2 D的rvalue引用”   一个类型为“cv1 B”的左值。   如果“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是对此对象的引用)。

答案 1 :(得分:-1)

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

{{1}}将生成编译器错误,但它不能保证在编译时或运行时转换有效。

由于TestDerived继承自TestBase,因此在static_cast运算符允许的情况下进行 legal 转换,但并非所有向下转换都必须是安全强制转换。

在上面的代码中,恰好安全地工作 - 很可能是因为TestMethod只访问基类成员,是单继承,没有vtable,也没有做任何复杂的事情。因此,编译器可能将转换视为无操作的简单示例。其他人会告诉你&#34;这是未定义的行为&#34; - 而不是假设任何关于这样写的代码。 (而且他们也是正确的。)