如何避免C++17中的虚拟继承?

让我们看看示例类。基类是ITransport,传输类接口:

class ITransport {
  public:
    virtual void move(const Path& p) = 0;
    virtual double estimateTime(const Path& path) = 0;
    /*Some more methods.*/
};

执行:

class Transport : public ITransport { 
  public:
    virtual void move(const Path& p) override {
        currPoint_ = p.lastPoint(); 
    }
    /*Some more methods.*/
  private:
    Point currPoint_;
};

我们还假设我们要创建一个自移动的运输类:

template <typename EnergySource>
class SelfMovingTransport : public Transport {
  /*Some special methods for self moving transport.*/
};

自动运输最简单的例子是汽车:

template <typename EnergySource>
class Car : public SelfMovingTransport <EnergySource> {
  public:
    virtual void visitCarService() = 0;
    /*Some more methods with logic for cars.*/
};

还需要造内燃机车……

class ICECar : public Car<Petrol> {
  public:
    virtual void move(const Path& p) override { 
        Transport::move(p);
        /*Some special methods for ICECar.*/ 
    }
    virtual void visitCarService() override { 
      /*Visit closest ICECar service.*/ 
    } 
    /*Some special methods for ICECar.*/
  private:
    Petrol::Amount petrol_;
};

...和电动汽车课程。

class ElectricCar : public Car<Electri?ity> {
  public:
    virtual void move(const Path& p) override { 
        Transport::move(p); 
        /*Some special methods for ElectricCar.*/ 
    }
    virtual void visitCarService() override { 
      /*Visit closest ElectricCar service.*/ 
    }
    /*Some special methods for ElectricCar.*/
  private:
    Electricity::Amount charge_; 
};

这个逻辑的延续可以是,例如,添加火车类等:

template <typename EnergySource>
class Train : public SelfMovingTransport<EnergySource> { 
  /*Not interesting.*/ 
};

我使用c++17编译器(MS)。不多也不少。

我想创建一个std::vector<Car*>指向不同类型汽车的指针数组(或),并为它们调用一些常用方法。例如,有一种简单的方法将它们全部发送到服务(请参阅 参考资料Car::visitCarServeice())。

我试过树的想法:

  • 创建类ISelfMovingTransportICar
class ISelfMovingTransport : public virtual ITransport { 
 /*All the same.*/ 
};
class ICar : public virtual ISelfMovingTransport { 
 /*All the same.*/ 
};

改为Transprot

class Transport : public virtual ITransport { 
 /* All the same. */
}

改为SelfMovingTransport

template <typename EnergySource>
class SelfMovingTransport : public ISelfMovingTransport, 
                            public Transport<EnergySource> {};

改为Car

template <typename EnergySource>
class Car: public ICar, public SelfMovingTransport<EnergySource> {
 /*All the same*/ 
};

最终解决方案没有奏效,因为static_cast
不能用于将指针强制转换为虚拟派生类指针(请参阅 pastebin链接。)。无法编译示例代码(错误:无法从指向基类“ISelfMovingTransport”的指针转换为指向派生类“ElectricCar”的指针,因为基类是虚拟的)。当我想执行ElectricCar作为指向 a 的指针访问的操作时Car,我需要
dynamic_cast<ElectricCar*>(carPtr)where carPtris of Car*。但是dynamic_cast是不允许的,RTTI是关掉的。

  • 使用std::vector<Transport*>对象并将其投射到Car. 它有效,但我不喜欢这个解决方案,因为很难检查一切是否正确。
  • 使用std::variant<ICECar, ElectricCar>std::visit。( std::visit([](auto& car) -> void { car.visitCarServeice(); }, carV)). (现在用这种方法实现。)。

在这个例子中(它代表了一个真实项目中的一个问题)我不想改变逻辑(尤其是从一个Transport级别到另一个级别的类Car)。

在没有 RTTI 和 dynamic_cast 的情况下,有没有一种通用的方法来做所需的事情?

std::variant在这种情况下是否“OK”(假设汽车类别不因大小和/或内存不同而不同)?

问的问题,因为不知道如何谷歌。

PS 所有示例都是真实项目中情况的表示(模拟等)。我请你想象一下真的需要能量类型作为参数,而不是考虑复杂性(混合动力汽车等)。

PPS 在实际项目中,我需要一个“汽车”的唯一对象作为其他类的字段。

回答

我想创建一系列不同类型的汽车。

你不能。数组在 C++ 中是同构的。所有元素始终具有相同的类型。

使用std::vector<Transport*>和投射对象到 Car

如果向量元素应该只指向汽车,那么使用指针来ICar代替似乎更有意义。此外,如果向量应该拥有指向的对象,那么您应该使用智能指针。并且您需要使析构函数成为虚拟的。

在没有 RTTI 和 dynamic_cast 的情况下,有没有一种通用的方法来做所需的事情?

通常是:虚函数。

在这种情况下 std::variant 是“OK”吗

如果变体的数量是一个小的常数,则可以。相比之下,继承层次结构允许添加任意多个子类。


以上是如何避免C++17中的虚拟继承?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>