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

Rrz*_*rz0 2 c++ inheritance

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

Road currentRoad = ...;
duration = ((SpeedDataRoad) currentRoad).getSpeedProfileTime(dateinMillis, isRightDirection);
Run Code Online (Sandbox Code Playgroud)

SpeedDataRoad继承自Road

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

     ...

}
Run Code Online (Sandbox Code Playgroud)

但是我得到了错误:

从“ Road”到“ SpeedDataRoad”的C样式转换没有匹配的转换

关于我在做什么错的任何建议将不胜感激。


需要明确的是,我试图用Java实现的内容将像这样编写并可以正常工作:

duration = ((SpeedDataRoad) currentRoad).getSpeedProfileTime(currentTime, isRightDirection);
Run Code Online (Sandbox Code Playgroud)

Aco*_*gua 5

您遭受一种称为“对象切片”的影响

SpeedDataRoad sdr;
Road currentRoad = sdr;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

SpeedDataRoad sdr;
Road& currentRoad = sdr;
//  ^ (!)
// or:
Road* currentRoad = &sdr;
Run Code Online (Sandbox Code Playgroud)

现在您可以进行投射了。但是明显的低调有不良设计的味道。从一开始就采用多态方法可能会更好:

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
    { /* ... */ }
};
Run Code Online (Sandbox Code Playgroud)

现在您可以简单地拥有:

SpeedDataRoad sdr;
Road& currentRoad = sdr;
double profile = currentRoad.getSpeedProfileTime(0, false);
Run Code Online (Sandbox Code Playgroud)

作为虚拟对象,无论我们拥有哪个子类,以及以哪种方式覆盖该函数,您都将始终获得该函数的正确变体...

旁注1:您可能更喜欢更现代的C ++强制转换,而不是旧的C样式强制转换,而是可以控制更细粒度的操作:

Road* someRoad = ...;
SpeedDataRoad* sdr = static_cast<SpeedDataRoad*>(someRoad);
SpeedDataRoad* sdr = dynamic_cast<SpeedDataRoad*>(someRoad);
Run Code Online (Sandbox Code Playgroud)

你会使用static_cast,如果你是100%肯定该对象可期望的类型。您可以避免在这种情况下根本无法提供任何服务的运行时测试(无论如何,您还是100%确定,记得吗?)。奇怪的是重复发生的模板模式是典型的情况。

如果不能确定类型,然后使用dynamic_cast它,它将进行一些运行时类型检查std::bad_cast,如果实际类型是,则返回一个空指针(如果用于指针)或抛出一个(如果用于引用)。不是期望的类型(或子类型)。当将不同的多态类型存储在向量中时,会出现这种情况(如指向基类的指针,请参见上文)。但是再次:完全需要转换可能暗示您的设计存在缺陷。

(为完整起见:还有const_castreinterpret_cast,但是您应该远离这些,除非/直到您真的非常了解自己的工作。)

旁注2:与Java的区别。

在Java中,我们在本机和引用类型之间进行隐式区分。本地的总是通过值传递,引用的类型总是通过引用传递–好吧,Java引用实际上比C ++引用更像C ++ 指针(可以是null,可以重新分配)。在Java中,这是隐式发生的,在C ++中,您需要明确说明(另一方面,对于任何类型,您都可以同时具有两种行为)。

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

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