【问题标题】:When and how is it decided to either use a cast or not?何时以及如何决定是否使用演员表?
【发布时间】:2016-11-16 00:33:40
【问题描述】:

我正在经历“Multiple Inheritance for C++ by Bjarne Stroustrup, Published in the May 1999 issue of "The C/C++ Users Journal"”。以下摘录来自相同(第 5/17 页),

4.4 铸造

显式和隐式转换还可能涉及使用 delta 修改指针值:

class A { void f(); };
class B { int f(); };
class C : A, B { };

C* pc;
B* pb; 
pb = (B*)pc; // pb = (B*)((char*)pc+delta(B)) 
pb = pc; // pb = (B*)((char*)pc+delta(B)) 
pc = pb; // error: cast needed <-------------------- HERE
pc = (C*)pb; // pc = (C*)((char*)pb-delta(B))

他向我们展示了 pb = pc 可以在不显式转换的情况下完成。这绝对意味着强制转换是隐式处理的。那么,

  1. 为什么,当我们尝试 pc = pb 指针时,是否需要强制转换?
  2. 指导这一点的规则是什么?在哪里?
  3. 是否与指针按增量值递增/递减有关?

编辑

Jonathan Mee 将此问题标记为“What Type of Cast to Go from Parent to Child?”的副本。我害怕,我不同意。我的问题是关于,为什么要施放,这条指导我们施放或不施放的规则在哪里。我认为背后的逻辑可能相同,但概念完全不同。在他的问题中,他对(坚持不使用动态转换)使用 dynamic_cast 和 static_cast 持怀疑态度。我的怀疑比他还差一些。

【问题讨论】:

  • 你会在这里有一个很好的解释:stackoverflow.com/questions/25137705/…
  • @JonathanMee - 我的问题是关于为什么要投射以及指导我们投射或不投射的规则在哪里。我认为背后的逻辑可能相同,但概念完全不同。我的怀疑与你的怀疑没有任何相似之处被标记为重复。在你的问题中,你知道你为什么要投射,但你对使用哪一个有疑问。我的怀疑仍然落后于你的一些步骤:)

标签: c++ pointers casting language-design language-concepts


【解决方案1】:

好吧,编译器知道指向C 的指针可以像继承的class AB 一样被引用——因此将向上 转换为AB 可以是隐式完成。换一种方式,编译器不知道指针指向C 的对象。它可能是一个不同的类,它也继承了A。通过添加演员表,您实际上是在说“别担心编译器 - 我知道它实际上是一个 C 类型的类”。

【讨论】:

  • so **casting down** to A or B can be done implicitly 我不认为,你的意思是向下转型。不过,感谢您的回答。
  • 哎呀。接得好。改变,
【解决方案2】:

在您的情况下,这很简单。您尝试将指向 B 类对象的指针分配给指向 C 类对象的指针。

你不能这样做,因为C 类的对象也提供A 类的功能,而B 类的对象没有。因此,使用 B 类的对象是未定义的,因为 B 无法提供 C 的所有内容。

【讨论】:

    【解决方案3】:

    这与我们知道对象具有的类型有关。每个C 也是一个B,因此转换总是有效(隐式)。

    每个B 都不是C 的一部分,所以你必须告诉编译器你确定这个特定的转换会起作用。这就是显式强制转换的使用。

    【讨论】:

    • 也许这超出了范围,但是当这样的强制转换(父 -> 子)无效时会发生什么行为?
    • 甜美而简单。我喜欢答案的“部分”部分。这无疑为隐式和显式演员阵容扫清了很多空气。
    【解决方案4】:

    The rules 关于允许的非基本类型的隐式转换如下:

    • 空指针可以转换为任何类型的指针
    • 指向任何类型的指针都可以转换为 void 指针。
    • 指针向上转换:指向派生类的指针可以转换为可访问且明确的基类的指针,而无需修改其constvolatile 限定条件。

    因此,当 向上转换C*B* 时,不需要显式转换。但由于从B* 转换为C* 是指针向下转换,因此可以使用C 样式转换,但首选以下方法之一:

    • dynamic_cast 可以使用,因为表达式是 B* 并且 new_type 是 C* 将执行此运行时检查,并且 1 应该允许向下转换:
    1. 检查表达式指向/标识的最派生对象。如果在该对象中,表达式指向/引用 Derived 的公共基,并且如果只有一个 Derived 类型的子对象是从表达式指向/标识的子对象派生的,则转换的结果指向/引用该 Derived 子对象。 (这被称为“沮丧”。)
    2. 否则,如果表达式指向/引用了最衍生对象的公共基类,并且同时,最衍生对象具有明确的 Derived 类型的公共基类,则转换的结果指向/引用该 Derived (这被称为“边播”。)
    3. 否则,运行时检查将失败。如果对指针使用dynamic_cast,则返回new_type类型的空指针值。
    • reinterpret_cast 可以使用,并且永远成功。但是只有在B 是 AliasedType 且 C 是 DynamicType 的情况下才定义使用它的结果,满足这些条件之一,第 2nd 个项目符号允许向下转换:
    • AliasedType 是(可能是 cv 限定的)DynamicType
    • AliasedType 和 DynamicType 都是指向同一类型 T 的(可能是多级的,可能是每个级别的 cv 限定的)指针
    • AliasedType 是 DynamicType 的(可能是 cv 限定的)有符号或无符号变体
    • AliasedType 是聚合类型或联合类型,将上述类型之一作为元素或非静态成员(递归地包括子聚合的元素和所包含联合的非静态数据成员):这使得它在给定指向其非静态成员或元素的指针的情况下,可以安全地获取指向结构或联合的可用指针。
    • AliasedType 是 DynamicType 的(可能是 cv 限定的)基类
    • AliasedType 是 charunsigned char:这允许将任何对象的对象表示形式检查为无符号字符数组。
    • 当且仅当B* 实际上是多态寻址C 对象时,也可以使用static_cast。如果不是这种情况并尝试static_cast,则会导致未定义的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多