【问题标题】:My teacher is not type-casting the same way as everyone else. Does anyone know what he is doing?我的老师不像其他人那样打字。有谁知道他在做什么?
【发布时间】:2018-05-30 20:16:12
【问题描述】:

我的老师在我们的一个选角示例中加入了以下几行。 c 是类 Circle 的一个对象,它继承自类 Point。在寻找“我可以将Point 类的对象转换为Circle 吗?”这个问题的答案时。我发现他使用的语法与我访问过的每个网站都不同。这些网站都使用static_castdynamic_cast 语法。他不会在测试中使用 static_cast 和 dynamic_cast ,我只是想知道他在使用什么以及它是如何运作的。

另外,如果您对我是否可以将基对象强制转换为派生类型有一个答案,我非常感谢您。

output << "the center of the circle is at " << (Point) c; 
// casting `Circle` object `c` with type `(Point)`, calls the first overloaded >stream insertion operator"

【问题讨论】:

  • Casting base to derived is UB,这就是你使用虚拟方法的原因。但这不是这里的情况,这是派生到基础的。
  • @PatrickRoberts 将基转换为使用此语法派生的格式不正确(即 (Derived)bstatic_cast&lt;Derived&gt;(b) 给出错误)

标签: c++ inheritance casting static-cast


【解决方案1】:

(Point)c 被称为“C 风格”演员表。这基本上可以被认为是一种蛮力施法,它尽其所能使施法成功。这意味着它最终可能会导致 static_cast const_cast 甚至 reinterpret_cast

当遇到 C 风格的转换表达式时,编译器会尝试将其解释为以下转换表达式,顺序如下:

  • const_cast
  • static_cast
  • static_cast 后跟 const_cast
  • reinterpret_cast
  • reinterpret_cast 后跟 const_cast

来源:https://en.cppreference.com/w/cpp/language/explicit_cast

来自 Stroustrup 本人:

最好避免显式类型转换(通常称为强制转换,以提醒您它们用于支撑损坏的东西)。

C 风格的转换应该被弃用,取而代之的是命名转换。

Stroustrup, Bjarne。 C++ 之旅(C++ 深度系列)(Kindle 位置 7134)。培生教育。 Kindle 版。

所以推荐使用命名的演员表。在实践中,我仍然会遇到使用 C 风格转换的专业代码,仅仅是因为它使代码更加简洁和可读,并且——如果你知道你在做什么——通常在它使用的地方等同于 static_cast。对于它的价值,我认为 C 风格的转换是可以的,如果出于这些原因在一个使得它很明显会导致 static_cast 的上下文中使用,并且 Stroustrup 来自一个过度的对象 -在他对选角的普遍蔑视中,有导向的视角。但你应该更喜欢命名的演员表。

您的老师可能正在使用 C 风格的演员表作为一种看起来不那么可怕的演员表介绍。

【讨论】:

  • “我需要一些不那么可怕的东西来教演员……我知道,我会使用传统的狼人演员,如果你用错误的方式摇晃它,它会直接把你扔到 UB 地!”啊,C++老师们……
  • 即使是正确的,我也不认为博客是很好的权威来源,尤其是当他们如此固执己见时
【解决方案2】:

到目前为止的答案并没有涵盖(Point) c; 的实际作用。假设Circle 没有明确定义operator Point

这与static_cast&lt;Point&gt;(c) 相同。它创建一个临时的Point 对象,该对象由Point 的复制构造函数初始化,c 作为参数。之所以可行,是因为基类复制构造函数无论好坏都可以绑定到派生对象。

需要明确的是,它不是对CirclePoint 部分的任何形式的引用。它正在复制CirclePoint 部分。这称为切片。它丢失了信息的所有“圆圈”部分。

我建议不要这样做。如果没有演员表,代码会更好。我想可能为PointCircle 定义了operator&lt;&lt; 重载,他想明确选择Point 之一;在这种情况下,您应该使用static_cast&lt;Point&amp;&gt;(c) 或等效的(Point&amp;)c 来查看圆而不是对其进行切片。

注意。首先从点派生圆也是可疑的;继承应该代表“is-a”关系(而不是“has-a”);但圆不是点。

延伸阅读:What is object slicing?

【讨论】:

    【解决方案3】:

    这是一个 C 风格的转换,如果可用,将使用“c.operator Point()”,否则它的行为与“reintrepret_cast(c)”相同

    【讨论】:

    • 不,它不会在这里做 reinterpret_cast。 Circle 派生自 Point,因此演员表进行直接转换,就像 Point p = c; 会做的那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    相关资源
    最近更新 更多