在C++中存储多种结构的模式 std::<vector> 容器
Pattern for storing multiple types of struct in a C++ std::<vector> container
我有一个表示火车的数据结构,它可以由多种类型的汽车组成,例如火车引擎、粮食车、客车等:
struct TrainCar {
// ...
Color color;
std::string registration_number;
unsigned long destination_id;
}
struct PowerCar : TrainCar {
// ...
const RealPowerCar &engine;
}
struct CargoCar : TrainCar {
// ...
const RealCargoCar &cargo;
bool full;
}
std::vector<TrainCar*> cars;
cars.push_back(new TrainCar(...));
cars.push_back(new TrainCar(...));
cars.push_back(new CargoCar(...));
cars.push_back(new CargoCar(...));
cars.push_back(new CargoCar(...));
算法将遍历列车上的车厢,并决定如何安排/分流每辆车厢(是否将其留在列车中,将其移动到列车的另一点,或将其从列车中移除)。这段代码看起来像:
std::vector<TrainCar*>::iterator it = cars.begin();
for (; it != cars.end(); ++it) {
PowerCar *pc = dynamic_cast<PowerCar*>(*it);
CargoCar *cc = dynamic_cast<CargoCar*>(*it);
if (pc) {
// Apply some PowerCar routing specific logic here
if (start_of_train) {
// Add to some other data structure
}
else if (end_of_train && previous_car_is_also_a_powercar) {
// Add to some other data structure, remove from another one, check if something else...
}
else {
// ...
}
}
else if (cc) {
// Apply some CargoCar routing specific logic here
// Many business logic cases here
}
}
我不确定这种模式(带有dynamic_cast和if语句链)是否是处理不同类型的简单结构体列表的最佳方式。dynamic_cast的用法似乎不正确。
一种选择是将路由逻辑移动到结构中(例如(*it)->route(is_start_of_car, &some_other_data_structure…)),但是如果可能的话,我希望将路由逻辑保持在一起。
有没有更好的方法来迭代不同类型的简单结构体(没有方法)?还是保留dynamic_cast方法?
这个问题的标准解决方案称为双重分派。基本上,您首先将算法包装在单独的函数中,这些函数为每种类型的汽车重载:
void routeCar(PowerCar *);
void routeCar(CargoCar *);
然后,向car添加一个route
方法,该方法在基类中是纯虚拟的,并在每个子类中实现:
struct TrainCar {
// ...
Color color;
std::string registration_number;
unsigned long destination_id;
virtual void route() = 0;
}
struct PowerCar : TrainCar {
// ...
const RealPowerCar &engine;
virtual void route() {
routeCar(this);
}
}
struct CargoCar : TrainCar {
// ...
const RealCargoCar &cargo;
bool full;
virtual void route() {
routeCar(this);
}
}
你的循环看起来像这样:
std::vector<TrainCar*>::iterator it = cars.begin();
for (; it != cars.end(); ++it) {
(*it)->route();
}
如果你想在运行时选择不同的路由算法,你可以将routeCar
-函数包装在一个抽象基类中,并提供不同的实现。然后将该类的适当实例传递给TrainCar::route
。
如果类的数量是可管理的,您可以尝试boost::variant
。
在c++中使用"sum类型"有时会很混乱,所以它要么是这个,要么是双调度。
经典的OO解决方案是生成所有相关的函数在TrainCar
的基类中创建virtual,并将具体逻辑放在每个基类中类。但是,您说希望保留路由逻辑如果可能的话一起。在某些情况下,这是合理的,而且这种情况下的经典解是一个变并(boost::variant
,例如)。哪一种对你比较好,由你来决定。
妥协也是可能的。例如,人们可以很容易地想象一个路由逻辑在某种程度上独立于汽车类型的情况(并且您不希望在每种汽车类型中都复制它),但它确实如此取决于一定数量的汽车类型的特点。在这个在这种情况下,TrainCar
中的虚函数可以简单地返回一个对象带有必要的依赖信息,供路由使用算法。这种解决方案的优点是减少了耦合在路由和TrainCar
之间达到最小需要。
取决于这个信息的性质,以及它是怎样的使用时,返回的对象可以是多态的,具有继承性反映TrainCar
的层次结构;在这种情况下,它必须是动态分配和管理:std::auto_ptr
被设计为我就是这么想的
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中用vector填充一个简单的动态数组
- vector.resize()中的分配错误
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 在某些循环内使用vector.push_back时出现分段错误
- 当vector是tje全局变量时,c++中vector的内存管理
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- std::vector的包装器,使数组的结构看起来像结构的数组
- 呼叫运营商<<临时
- 为什么(-1)%vector::size()总是返回0
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在C++中将类(带有Vector成员)保存为二进制文件
- 编译器如何区分std::vector的构造函数
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 错误:调用"std::vector<:vector<int>>::p ush_back(std::vector<std::__cxx11::basic_string<
- std::vector::reserve(未知m),我知道m<<;N(通常)并且知道N
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- C++重载<<具有typedef'd std::vector
- std::映射<>或std::vector<>在处理大型标志集时