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

How to avoid virtual inheritance in C++17?

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

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_;
};

我们也假设我们想要创建一个自动移动的交通工具 class:

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.

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_; 
};

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

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

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

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

我试过树的想法:

class ISelfMovingTransport : public virtual ITransport { 
 /*All the same.*/ 
};
class ICar : public virtual ISelfMovingTransport { 
 /*All the same.*/ 
};

Changed Transprot to:

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

Changed SelfMovingTransport to:

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

Changed Car to:

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

In the end solution did not work, because static_cast can not be used to cast pointer to virtually derived class pointer (See pastebin link.). Example code can't be compiled (error: cannot convert from pointer to base class ‘ISelfMovingTransport’ to pointer to derived class ‘ElectricCar’ because the base is virtual). When I want to make actions with ElectricCar which is accessed as a pointer to a Car, I need dynamic_cast<ElectricCar*>(carPtr) where carPtr is of Car*. But dynamic_cast is not allowed, RTTI is turned off.

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

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

std::variant 'OK'这种情况(假设车class是不 大小不同 and/or 内存不重要)?

问的问题,因为不知道怎么google那个。

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

P.P.S。在实际项目中我需要一个“汽车”的唯一对象作为其他class.

的字段

I want to create an array of cars of different types.

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

Use std::vector<Transport*> and cast objects to Car

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

Is there a common way to do required things without RTTI and dynamic_cast?

通常是:虚拟函数。

Is std::variant 'OK' in this situation

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

我相信这解决了您的问题,但很难说。它去除了代码中的一些细节,但演示了该技术。它使用 std::variantstd::visit.

#include <iostream>
#include <memory>
#include <variant>

class Car {
public:
    Car( ) = default;
};

class ICECar : public Car {
public:
    ICECar( ) {
    }
    void visitCarService( ) {
        std::cout << "ICE visitCarService\n";
    }
};

class ECar : public Car {
public:
    ECar( ) {
    }
    void visitCarService( ) {
        std::cout << "E visitCarService\n";
    }
};

using car_variant = std::variant<
    std::shared_ptr<ICECar>,
    std::shared_ptr<ECar>>;

template <size_t C>
void visitCarService(std::array<car_variant, C>& cars) {
    for (auto& c : cars) {
        std::visit(
            [](auto&& arg) {
                arg->visitCarService( );
            },
            c);
    }
}

int main(int argc, char** argv) {

    ICECar ice_car { };
    ECar e_car { };

    std::array<car_variant, 2> cars {
        std::make_shared<ICECar>(ice_car),
        std::make_shared<ECar>(e_car)
    };

    visitCarService(cars);

    return 0;
}

这是使用 GCC 11 编译的,使用 std=c++17 和 -pedantic 集。大概它应该在 MS 下编译。 Here 是它的在线 运行。