微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决如何避免 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 link。)。 无法编译示例代码错误:无法从指向基类“ISelfMovingTransport”的指针转换为指向派生类“ElectricCar”的指针,因为基类是虚拟的)。 当我想用 ElectricCar 进行操作时 作为指向 Car 的指针访问,我需要 dynamic_cast<ElectricCar*>(carPtr) 其中 carPtrCar*。 但不允许使用 dynamic_castRTTI关闭

  • 使用 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”(假设汽车类没有 大小不同和/或内存不重要)?

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

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

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

解决方法

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

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

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

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

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

通常是:虚函数。

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

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

,

我相信这解决了您的问题,但很难说。它删除了代码中的一些细节,但演示了该技术。它使用 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 是它的在线运行。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。