【问题标题】:Is this downcasting undefined?这是向下转换未定义吗?
【发布时间】:2015-11-08 18:11:51
【问题描述】:

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

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 它具有未定义的行为。但是这种情况是否有例外,派生类的布局与基类的布局相同?

【问题讨论】:

标签: c++ undefined-behavior downcast


【解决方案1】:

来自标准(强调我的):

§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”类型的 xvalue 可能是 强制转换为类型“对 cv2 D 的右值引用”,具有与 for 相同的约束 “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();
}

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

【讨论】:

  • “b”实际上是 TestDerived 类型对象的子对象吗?
  • 粗体字表示该示例无效有效
【解决方案2】:

static_cast&lt;&gt; 如果您尝试在不兼容的类型之间进行转换,将生成编译器错误,但它不保证在编译时或运行时转换是有效的。

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

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

【讨论】:

  • 这里dynamic_cast 不起作用,因为TestBase 不是多态的。
  • 这是不正确的,强制转换本身会导致未定义的行为(请参阅 sergej 答案中的粗体文本)
  • 我相信这个答案很好地描述了大多数实现实际上会做什么,但没有抓住问题的重点。 可预测 != 已定义.
  • @ams - 这是很好的反馈。我尝试从编译器和链接器如何在现代计算机上实际工作的角度给出关于 SO 的实用答案。它可以更深入地了解 C/C++ 的实际实现方式——这反过来又可以使人们更好地调试和分析代码。但是,如果 C/C++ 标记中存在很多 语言律师,他们会否决任何此类讨论,如果它符合“标准所说的”这一事实。当这个小组在场时,我在给出实际答案时必须小心行事。
  • 这很好,但是你需要明确地说出来并理解你自己,你在打赌没有人会改变任何打破你假设的东西(无论是在你的代码和编译器中) )。
猜你喜欢
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 1970-01-01
  • 2023-01-27
  • 1970-01-01
相关资源
最近更新 更多