【问题标题】:Casting - Why Should I do it for UpcastingCasting - 我为什么要为 Upcasting 做这件事
【发布时间】:2013-04-29 18:49:38
【问题描述】:

我一直在阅读此站点上的其他一些帖子,其中提到了 dynamic_cast 和 static_cast 都可以安全地向上转换。

为什么向上转换需要这些?

例如,如果类 B 是从 A 派生的,那么

A * ptr = new B ();

仍然有效,并且表现得像 A 类型的对象。(我也来自 Java 背景,不需要向上转换的转换。

我还在这个网站上读到,向下转换不需要 dynamic_cast [in question "When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?"] .同样,我认为只有在向下转换时才真正需要转换,因为向上转换会自动发生。

我哪里错了?

【问题讨论】:

  • 注意:在上一个问题中,其中一个答案是“您不必使用它来向下投射......”。但是,从完整句子的上下文来看,意思是您不仅限于将其用于向下投射。 [我已经编辑了那个答案以消除歧义。]

标签: c++ oop inheritance polymorphism


【解决方案1】:

如果您有复杂的继承层次结构,默认向上转换行为可能不起作用。例如:

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};

在该层次结构中,D 类型的对象有两个不同的A 类型基。从D* 到A* 的转换是不明确的。对于这种情况,您可以强制执行中间步骤

A *p = static_cast<B*>(d);   // Give me the 'A' subobject within 'B'

类似地,如果有一个函数具有多个重载,可以采用基类型或派生类型,并且您需要调用采用基类型的版本(注意:这里有代码味道!),那么您可以使用强制转换来指示重载决议。同样,如果您需要直接解决重载问题,您可能做错了什么。

除了极端情况(即默认向上转换不起作用时),实际上没有理由明确使用转换操作,我实际上建议不要这样做,因为转换应该是一个警告灯,过度使用它们可能会导致它们正常读取代码时不会发出警报。

【讨论】:

  • 很好的极端案例示例,但我会质疑它的实际相关性,因为这是无论如何都不应该出现在你的代码库中的糟糕代码(死亡的钻石)——至少与 upcast 结合使用。跨度>
【解决方案2】:

在多重继承的情况下(Java 并不真正拥有),您可能会调整“this”指针。在那种情况下, reinterpret_cast 是不安全的,这就是他们试图通过说 static_cast 和 dynamic_cast 是安全的来强调的。

顺便说一句,在对要移植到 Android-without-dynamic_cast 的代码库的调查中,我发现了 127 个 dynamic_cast,其中 122 个实际上是不必要的。这是由非常精通 C++ 的人编写的代码。

【讨论】:

    【解决方案3】:

    为什么向上转换需要这些?

    它们不是,并且将它们用于向上转换是(恕我直言)误导:不需要转换出于某种原因:从逻辑上讲,子类对象是超类的实例。

    总之,我不鼓励明确的向上转型。对于坚持我至少要求一致性的人:在任何地方都使用显式向上转换,包括在初始化中:

    A * ptr{static_cast<A*>(new B)};
    

    大多数人都会同意这很愚蠢。

    【讨论】:

    • 我就是这么想的。但是,为什么一个有 673 个赞成票的答案会说“你不必用它来向下投射”关于动态投射 stackoverflow.com/questions/332030/…。没有在那个帖子上发帖,因为我认为我的理解存在根本性错误
    • @user929404 你误解了这个答案——实际的信息是reinterpret_cast 不仅适用于向下转换,它还可以执行其他转换。但是,该帖子并没有说明实际上 拥有 将其用于上播(但是,其他在线 cmets 确实建议这样做)。
    猜你喜欢
    • 1970-01-01
    • 2014-12-09
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    相关资源
    最近更新 更多