如何在C++代码中避免使用dynamic_cast?

Mic*_*fik 18 c++ oop inheritance dynamic-cast car-analogy

假设我有以下类结构:

class Car;
class FooCar : public Car;
class BarCar : public Car;

class Engine;
class FooEngine : public Engine;
class BarEngine : public Engine;
Run Code Online (Sandbox Code Playgroud)

我们也给它Car一个句柄Engine.FooCar将使用a创建A ,FooEngine*并使用a BarCar创建BarEngine*.有没有办法安排事情,所以一个FooCar对象可以调用成员函数而FooEngine无需向下转换?

这就是为什么类结构按照现在的方式布局的原因:

  1. 所有人Car都有Engine.此外,一个FooCar只会使用一个FooEngine.
  2. 所有人都共享数据和算法Engine,我宁愿不复制和粘贴.
  3. 我可能想写一个需要Engine了解它的函数Car.

一旦我dynamic_cast在编写这段代码时输入,我就知道我可能做错了什么.有一个更好的方法吗?

更新:

根据目前给出的答案,我倾向于两种可能性:

  1. Car提供一个纯虚getEngine()函数.这将允许FooCarBarCar具有返回正确类型的实现Engine.
  2. 将所有Engine功能吸收到Car继承树中. Engine因维护原因而被打破(将这些Engine东西放在一个单独的地方).这是在拥有更多小类(代码行数较少)与较少大类之间的权衡.

是否有强烈的社区偏好这些解决方案之一?我还没有考虑过第三种选择吗?

Dre*_*ann 24

我假设Car拥有一个引擎指针,这就是为什么你会发现自己的低迷.

将指针从基类中取出,并将其替换为纯虚拟get_engine()函数.然后你的FooCar和BarCar可以保持指向正确引擎类型的指针.

(编辑)

为什么这样有效:

由于虚函数Car::get_engine()将返回引用或指针,因此C++将允许派生类使用不同的返回类型实现此函数,只要返回类型仅因更多派生类型而不同.

这称为协变返回类型,并允许每种Car类型返回正确的Engine.

  • 由于虚函数允许协变返回类型,因此您可以使返回的值为适当的FooEngine或BarEngine类型!我忽略了这个简单解决方案的+1. (5认同)

cle*_*tus 10

我只想补充一点:这个设计对我来说已经闻起来很糟糕,因为我称之为并行树.

基本上,如果您最终得到并行类层次结构(就像您使用Car和Engine一样),那么您只是在寻找麻烦.

如果Engine(甚至是Car)需要有子类,或者那些只是相同的基类的不同实例,我会重新考虑.

  • 你能提供一个具体的例子(根据上面我的类结构)如何解决"并行树"问题? (2认同)

Joh*_*McG 7

您还可以按如下方式对引擎类型进行模板化

template<class EngineType>
class Car
{
    protected:
        EngineType* getEngine() {return pEngine;}
    private:
        EngineType* pEngine;
};

class FooCar : public Car<FooEngine>

class BarCar : public Car<BarEngine>
Run Code Online (Sandbox Code Playgroud)


Sri*_*yer 5

我不明白为什么汽车不能由引擎组成(如果 BarCar 总是包含 BarEngine)。发动机与汽车有着非常密切的关系。我会比较喜欢:

class BarCar:public Car
{
   //.....
   private:
     BarEngine engine;
}
Run Code Online (Sandbox Code Playgroud)