首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何避免C++17中的虚拟继承?

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

Stack Overflow用户
提问于 2021-07-29 23:41:14
回答 2查看 418关注 0票数 6

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

代码语言:javascript
复制
class ITransport {
  public:
    virtual void move(const Path& p) = 0;
    virtual double estimateTime(const Path& path) = 0;
    /*Some more methods.*/
};

执行情况:

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

让我们想象一下,我们想要创建一个自移动传输类:

代码语言:javascript
复制
template <typename EnergySource>
class SelfMovingTransport : public Transport {
  /*Some special methods for self moving transport.*/
};

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

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

还需要用内燃机制造汽车..。

代码语言:javascript
复制
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_;
};

..。还有一辆电动汽车。

代码语言:javascript
复制
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_; 
};

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

代码语言:javascript
复制
template <typename EnergySource>
class Train : public SelfMovingTransport<EnergySource> { 
  /*Not interesting.*/ 
};

我使用c++17压缩器(MS)。不要少,不要多。

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

我试过树的想法:

  • 创建类ISelfMovingTransportICar

类ISelfMovingTransport :公共虚拟ITransport { /*All相同.*/ };类ICar :公共虚拟ISelfMovingTransport { /*All相同.*/ }; 将Transprot更改为: 类传输:公共虚拟ITransport { /*。*/ } 将SelfMovingTransport更改为: 模板类SelfMovingTransport :公共ISelfMovingTransport,公共传输{}; 将Car更改为: 模板类Car:公共ICar,公共SelfMovingTransport { /*All相同*/ }; 最终解决方案不起作用,因为static_cast不能用于将指针转换到实际派生的类指针(请参阅pastebin 链接.)。示例代码无法编译(错误:不能从指针转换为基类“ISelfMovingTransport”到派生类“ElectricCar”,因为基是虚拟的)。当我想使用作为指向ElectricCar的指针访问的Car进行操作时,我需要dynamic_cast<ElectricCar*>(carPtr)carPtr位于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‘(假设car类的大小和/或内存不重要)吗?

问个问题,因为我不知道怎么用谷歌搜索。

所有的例子都是表示(模拟,等等)真实项目中的情况。我要求你们想象能源类型作为参数是真正需要的,而不是考虑复杂的问题(混合动力汽车等等)。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-08-04 02:29:26

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

代码语言:javascript
复制
#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集编写。据推测,它应该在这里女士下编译,这是一个在线运行的版本。

票数 1
EN

Stack Overflow用户

发布于 2021-07-30 00:17:34

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

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

对Car使用std::vector<Transport*>和cast对象

如果向量元素只指向cars,那么使用指向ICar的指针似乎更有意义。此外,如果向量应该拥有指定的对象,那么您应该使用智能指针。你需要把析构函数变成虚拟的。

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

通常是:虚拟函数。

在这种情况下,变体'OK‘是:

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

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68583876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档