用于在C++ std :: <vector>容器中存储多种类型的结构的模式

che*_*ers 4 c++ design-patterns

我有一个代表火车的数据结构,它可以由许多类型的汽车组成,例如火车引擎,谷物汽车,乘用车等等:

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(...));
Run Code Online (Sandbox Code Playgroud)

算法将遍历列车中的汽车,并决定如何路由/分流每辆车(是否将其保留在列车中,将其移至列车中的另一个点,将其从列车中移除).此代码如下所示:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定这种模式(使用dynamic_casts和if语句链)是否是处理不同类型的简单结构列表的最佳方法.使用dynamic_cast似乎不正确.

一种选择是将路由逻辑移动到结构(就像(*it) - > route(is_start_of_car,&some_other_data_structure ...)),但是如果可能的话我想将路由逻辑保持在一起.

有没有更好的方法来迭代不同类型的简单结构(没有方法)?或者我是否保持dynamic_cast方法?

Bjö*_*lex 8

对此的标准解决方案称为双重调度.基本上,您首先将算法包装在针对每种类型的汽车重载的单独函数中:

void routeCar(PowerCar *);
void routeCar(CargoCar *);
Run Code Online (Sandbox Code Playgroud)

然后,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);
   }
}
Run Code Online (Sandbox Code Playgroud)

你的循环看起来像这样:

std::vector<TrainCar*>::iterator it = cars.begin();
for (; it != cars.end(); ++it) {
    (*it)->route();
}
Run Code Online (Sandbox Code Playgroud)

如果要在运行时选择不同的路由算法,可以将routeCar-functions 包装在抽象基类中,并为其提供不同的实现.然后,您将该类的相应实例传递给TrainCar::route.