C 映射类成号码

c++ Mapping class to number

本文关键字:号码 映射      更新时间:2023-10-16

i最近从C 开发开始。我遇到了一个无法解决问题的问题,因为我不知道是否可能。

我想在数字和类之间创建一个映射,这些映射是从抽象类得出的。

本质上,我想做的就是创建一种工厂方法,该方法可以基于与该类关联的给定编号创建类的新实例。

我知道我可以做以下...

Vehicle *Vehicle::from_type(byte type)
{
    switch(type)
    {
        case 0x00: return new Bicyle();
        case 0x01: return new Car();
        ...
        case 0x10: return new Truck();
    }
    return null;
}

...,但我不想让它保持干燥。

在某种程度上,人们可以按照此操作来做些事情:

// I know this is incorrect syntax
const map<byte, class extends Vehicle> VEHICLE_MAPPING = {{0x00, Bicyle}, {0x01, Car}, ..., {0x10, Truck}};
Vehicle *Vehicle::from_type(byte type)
{   
    return new VEHICLE_MAPPING[type]();
}

我可以看到您的方法如何与std::map<uint8_t, std::unique_ptr<Vehicle>>的使用一起使用,但是存在问题 - 您将无法使用initializer_list初始化该映射,因为它 copies copies 元素,众所周知,std::unique_ptr无法复制。您将必须创建一个init()函数才能初始化将使用与Vehicle *Vehicle::from_type(byte type)相似的逻辑的地图,这简直是毫无意义的。

此外,我不同意您的第一个解决方案违反了干燥。实际上,这是正确的,从某种意义上说,您不会被迫在代码中其他位置使用switchif S。我一定会坚持下去。

最终注释 - 您可以使用std::map<uint8_t, std::shared_ptr<Vehicle>>代替std::map<uint8_t, std::unique_ptr<Vehicle>>并使用initializer_list初始化,因为std::shared_ptr 可以复制,但我不建议这样做,因为它是错误的表示shared_ptr的用法。如果您以某种方式被迫这样做,这里是一个例子:

class Base{ public: virtual ~Base() = default; };
class Derived1 : public Base{};
class Derived2 : public Base{};
class derived_factory{
    private:
        derived_factory();
        static inline std::map<uint8_t, std::shared_ptr<Base>> base_map = {
            {0x00, std::make_shared<Derived1>()},
            {0x01, std::make_shared<Derived2>()}
        };
    public:
        static std::unique_ptr<Base> from_type(uint8_t type)
        {
            return std::make_unique<Base>(*base_map[type]);
        }
};
int main()
{
    auto ptr = derived_factory::from_type(0x00);
    // ptr is of a type std::unique_ptr<Base> and points to Derived1 object
}

其他应该是最终使用此解决方案的问题是它的速度很慢。它在地图中构造对象,除了将它们保留为"模板"复制示例之外,它们没有任何作用。

如果它们都是从基类得出的,则可以使用工厂模式,例如,从loki的实现中使用(请参阅现代C 设计有关详细信息,虽然那本书是pre-c 11)。

以下会创建一些混凝土车辆,并将其放入向量,然后在其中调用drive()方法:

#include <iostream>
#include <memory>
#include <vector>
#include "factory.h"
struct Vehicle
{
  virtual ~Vehicle() = default;
  virtual void drive() = 0;
};
struct Car : Vehicle
{
  static constexpr auto ID = 1;
  void drive() override { std::cout << "Carn"; }
};
struct Truck : Vehicle
{
  static constexpr auto ID = 2;
  void drive() override { std::cout << "Truckn"; }
};
// Create the factory object
auto g_factory = MyUtil::Factory<std::unique_ptr<Vehicle>, int>{};
void RegisterTypesWithFactory()
{
    // We pass in creator functions for each type. Note that these
    // could be lambdas or some other freestanding function and they
    // could accept parameters.
    g_factory.Register( Car::ID,   &std::make_unique<Car> );
    g_factory.Register( Truck::ID, &std::make_unique<Truck> );
}
int main()
{
    // Configure the factory
    // Note: Registration can be done any time, e.g., later based on input 
    // from a file. I do them all at once here for convenience of illustration.
    RegisterTypesWithFactory();
    // Create some objects with the factory
    auto vehicles = std::vector<std::unique_ptr<Vehicle>>{};
    vehicles.emplace_back( g_factory.Create( Car::ID ) );
    vehicles.emplace_back( g_factory.Create( Truck::ID ) );
    // Do something with the objects
    for( const auto& v : vehicles )
    {
        v->drive();
    }
}

打印:

Car
Truck

看到它在 wandbox 中实时运行。