Гео*_*нов 7 c++ multiple-inheritance rtti c++17
让我们看看示例类。基类是ITransport,传输类接口:
class ITransport {
public:
virtual void move(const Path& p) = 0;
virtual double estimateTime(const Path& path) = 0;
/*Some more methods.*/
};
Run Code Online (Sandbox Code Playgroud)
执行:
class Transport : public ITransport {
public:
virtual void move(const Path& p) override {
currPoint_ = p.lastPoint();
}
/*Some more methods.*/
private:
Point currPoint_;
};
Run Code Online (Sandbox Code Playgroud)
我们还假设我们要创建一个自移动的运输类:
template <typename EnergySource>
class SelfMovingTransport : public Transport {
/*Some special methods for self moving transport.*/
};
Run Code Online (Sandbox Code Playgroud)
自动运输最简单的例子是汽车:
template <typename EnergySource>
class Car : public SelfMovingTransport <EnergySource> {
public:
virtual void visitCarService() = 0;
/*Some more methods with logic for cars.*/
};
Run Code Online (Sandbox Code Playgroud)
还需要造内燃机车……
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_;
};
Run Code Online (Sandbox Code Playgroud)
...和电动汽车课程。
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_;
};
Run Code Online (Sandbox Code Playgroud)
这个逻辑的延续可以是,例如,添加火车类等:
template <typename EnergySource>
class Train : public SelfMovingTransport<EnergySource> {
/*Not interesting.*/
};
Run Code Online (Sandbox Code Playgroud)
我使用c++17编译器(MS)。不多也不少。
我想创建一个std::vector<Car*>指向不同类型汽车的指针数组(或),并为它们调用一些常用方法。例如,有一种简单的方法将它们全部发送到服务(请参阅 参考资料Car::visitCarServeice())。
我试过树的想法:
ISelfMovingTransport和ICar:Run Code Online (Sandbox Code Playgroud)class ISelfMovingTransport : public virtual ITransport { /*All the same.*/ }; class ICar : public virtual ISelfMovingTransport { /*All the same.*/ };改为
Transprot:Run Code Online (Sandbox Code Playgroud)class Transport : public virtual ITransport { /* All the same. */ }改为
SelfMovingTransport:Run Code Online (Sandbox Code Playgroud)template <typename EnergySource> class SelfMovingTransport : public ISelfMovingTransport, public Transport<EnergySource> {};改为
Car:Run Code Online (Sandbox Code Playgroud)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)wherecarPtris ofCar*。但是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”吗
如果变体的数量是一个小的常数,则可以。相比之下,继承层次结构允许添加任意多个子类。
我相信这解决了你的问题,但很难说。它删除了代码中的一些细节,但演示了该技术。它使用std::variant和std::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;
}
Run Code Online (Sandbox Code Playgroud)
这是使用 GCC 11 使用 std=c++17 和 -pedantic 集进行编译的。大概应该在 MS 下编译。这是它的在线运行。