c++ - 如何在 C++ 中向下转换以从父实例调用子函数?

标签 c++ inheritance

我正在尝试使用显式向下转换从父实例调用子函数(感谢指出@Aconcagua)。作为 C++ 的初学者,我有这样的事情:

Road currentRoad = ...;
duration = ((SpeedDataRoad) currentRoad).getSpeedProfileTime(dateinMillis, isRightDirection);

SpeedDataRoad 继承自 Road:

class SpeedDataRoad : public Road{ 
     double getSpeedProfileTime(long dateinMillis, bool isRightDirection) {

     ...

}

但是我得到了错误:

No matching conversion for C-style cast from 'Road' to 'SpeedDataRoad'

如有任何关于我做错的建议,我们将不胜感激。


需要说明的是,我想用 Java 实现的目标应该是这样写的并且可以正常工作:

duration = ((SpeedDataRoad) currentRoad).getSpeedProfileTime(currentTime, isRightDirection);

最佳答案

您受到称为“对象切片”的影响:

SpeedDataRoad sdr;
Road currentRoad = sdr;

在第二行,sdr按值 分配给 currentRoad,但后者的类型不适合保存完整的 SpeedDataRoad 对象。所以 SpeedDataRoad 的所有多余部分都被简单地切掉了,剩下的只是一个纯 Road 对象,只包含原始 Road 部分sdr 对象。

同时,由于您只剩下一个纯 Road 对象,您不能将其转换回 SpeedDataRoad 对象。现在缺少的部分应该从哪里来?

这与不能将多态类型直接放入基类的容器(如 std::vector)的原因完全相同。

您需要的是指针(如果您希望能够重新分配)或引用(否则是首选):

SpeedDataRoad sdr;
Road& currentRoad = sdr;
//  ^ (!)
// or:
Road* currentRoad = &sdr;

现在您可以进行转换了。但是显式的向下转换有一种糟糕设计的味道。从一开始就采用多态方法可能会更好:

class Road
{
public:
    virtual double getSpeedProfileTime(long, bool) = 0;
    //                                             ^ pure virtual
    // alternatively, you can provide a default implementation
};

class SpeedDataRoad : public Road
{
public:
    double getSpeedProfileTime(long, bool) override
    { /* ... */ }
};

现在您可以简单地拥有:

SpeedDataRoad sdr;
Road& currentRoad = sdr;
double profile = currentRoad.getSpeedProfileTime(0, false);

作为虚函数,无论我们拥有哪个子类以及它可能以何种方式重写函数,您都将始终获得函数的正确变体...

旁注 1:您可能更喜欢更现代的 C++ 类型转换,而不是旧的 C 风格类型转换,您可以控制更细粒度的实际操作:

Road* someRoad = ...;
SpeedDataRoad* sdr = static_cast<SpeedDataRoad*>(someRoad);
SpeedDataRoad* sdr = dynamic_cast<SpeedDataRoad*>(someRoad);

您可以使用static_cast,如果您 100% 确定对象 可以是所需的类型。您可以避免在这种情况下根本无法提供任何服务的任何运行时测试(无论如何您都 100% 确定,还记得吗?)。 Curiously recurring template pattern是一个典型的场景。

如果你不能确定类型,那么 dynamic_cast 开始发挥作用,它会做一些运行时类型检查并只返回一个空指针(如果用在指针上)或抛出一个 std::bad_cast(如果用于引用),如果实际类型不是所需类型(或其子类)。当不同的多态类型存储在一个 vector 中(作为指向基类的指针,见上文)时,就会出现这种情况。但同样:根本需要类型转换可能暗示您的设计存在缺陷......

(为了完整性:还有 const_castreinterpret_cast,但你应该远离这些,除非/直到你真的,真的知道你做什么。)

旁注 2:与 Java 的差异。

在 Java 中,我们隐式区分 native 类型和引用类型。 native 类型始终按值传递,引用类型始终按引用传递 - 好吧,Java 引用,它实际上更类似于 C++ 指针(可以是null,可以重新分配)而不是 C++ 引用。在 Java 中,这隐式发生,在 C++ 中,您需要明确(另一方面,任何类型都可以有这两种行为)。

Java 在 (Java!) 引用上的转换行为类似于 C++ dynamic_cast(在引用上,即抛出,它不会在类型不匹配时返回 null)。

最后(关于我的多态性建议),在 Java 中所有函数都是隐式虚拟的,在 C++ 中,您必须再次明确(应用 virtual 关键字,请参阅以上)。

关于c++ - 如何在 C++ 中向下转换以从父实例调用子函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57657546/

相关文章:

c++ - 从 QGraphicsScene 中删除所有行

Ruby 错误处理 : Rescuing Exceptions in Subclasses

ruby - 使用多级继承而不是 ruby​​ mixins

Python 2.7 访问父类(super class)属性不是 DRY?

c++ - 实现基类比较的正确方法是什么?

c++ - 将 QString 转换为 uint16*

c++ - 反向位算法

c++ - OpenGL SuperBible 第 6 版,缺少头文件 sb6.h

c++ - 当 A 和 B 没有共同的祖先时,通过 dynamic_cast 从 A* 转换为 B* 是否有效?

c++ - Switch case 程序在某个点不断循环。想不通