首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我可以使用map<char[2]、class>中的类类型作为容器吗?

我可以使用map<char[2]、class>中的类类型作为容器吗?
EN

Stack Overflow用户
提问于 2016-05-19 15:55:54
回答 2查看 58关注 0票数 1

我想要做的是:从XML文件加载数据(这很好)。XML告诉程序创建类实例(来自特定的不同类,如CarPlane),然后这些类实例将存在于程序中。这些类实例对象是总体Object基类的子类。

XML文件以数字的形式存储需要创建的对象类型,程序将从中决定要创建哪一类对象。

我可以使用switch语句并枚举所有类型的对象,但是当添加大量对象实例时,这会极大地影响性能。因此,我希望从char[2]映射到所需的类。(注意:类类型本身,而不是类的实例。)

例如,如果XML属性表示'type=0x01',那么将从类Car生成一个对象,而如果'type=0x02‘则将生成一个Plane对象。(两者都是Object的一种)

通过这种方式,我想使用一个常量映射来完成这个任务。我想写点什么

代码语言:javascript
复制
map<char[2],class> ObjectsList = {
     {0x01,Car},
     {0x02,Plane}
     //etc, etc.
}

...
// while loading data from xml file on which objects need to get created,
// an object-tag gives data from 'type' attribute, and the program stores
// it in 'char[2] type';
char[2] type = getattributestufffromxml("type");
ObjectsList[type] newObject = memoryallocator.allocate(sizeof(ObjectsList[type]);
newObject.Init(); //inherited function from Object

这样做的目的是创建一种更快的方法,而不是停留在开关语句上,这在创建数百个对象时是很糟糕的。

我需要做些什么才能从上面得到一个有效的C++?我不知道如何在地图中存储类类型。(我得到编译器错误,例如“参数2/4无效”)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-19 16:15:54

我不知道如何在地图中存储类类型。(我经常得到“参数2/4无效”)

嗯,char[2]数组不能用作std::map::key_type,因为它不能满足 concept的必要约束。

从您的初始化程序列表中,它看起来仍然需要一个uint8_t作为键值。

此外,您也不能将类型作为值存储在映射中。

如果要为构造函数使用函数指针,则that's not possible,因为构造函数和析构函数是特殊的类(不返回类型甚至不是void),而且不能用函数指针引用它们。

我认为您实际上需要的是一个与std::map对应的enum存储工厂函数,如下所示:

代码语言:javascript
复制
enum class VehicleTypes : uint8_t {
    CarType = 0x01 ,
    PlaneType = 0x02 ,
}; 

struct Vehicle {
     virtual ~Vehicle() {}
     virtual void Init() = 0;
};

typedef std::function<Vehicle*()> CreateVehicleFn;

class Car : public Vehicle {
public:
     virtual void Init() {
         // do anything necessary to init a Car
     }
};

class Plane : public Vehicle {
public:
     virtual void Init() {
         // do anything necessary to init a Plane
};

std::map<VehicleTypes,CreateVehicleFn> CreatorFnList = 
     { { VehicleTypes::CarType, []() { return new Car(); } } ,
       { VehicleTypes::PlaneType, []() { return new Plane(); } }
     };

后一个映射初始化列表并不比您在(伪)代码示例中提供的代码多多少。

如果你想摆脱锅炉板的东西,并且认为它值得混淆你的代码,你仍然可以使用宏:

代码语言:javascript
复制
#define Create(classtype) []() { return new classtype(); }

std::map<VehicleTypes,CreateVehicleFn> CreatorFnList = 
     { { VehicleTypes::CarType, Create(Car) } ,
       { VehicleTypes::PlaneType, Create(Plane) }
     };

然后,您可以使用它创建新实例,具体取决于键参数:

代码语言:javascript
复制
Plane* plane = dynamic_cast<Plane*>(CreateVehicleFn[VehicleTypes::PlaneType]());
if(plane) {
    plane->Init();
}

为了提供清晰的所有权语义,甚至可以考虑使用std::unique_ptr<Vehicle>将新实例从工厂传递到客户端:

代码语言:javascript
复制
typedef std::function<std::unique_ptr<Vehicle>()> CreateVehicleFn;

std::map<VehicleTypes,CreateVehicleFn> CreatorFnList = 
     { { VehicleTypes::CarType, []() { return make_unique<Car>(); } } ,
       { VehicleTypes::PlaneType, []() { return make_unique<Plane>(); } }
     };

使用的语法与我的第一个示例的语法大致相同:

代码语言:javascript
复制
std::unique_ptr<Plane> plane = CreateVehicleFn[VehicleTypes::PlaneType]();
if(plane.get()) {
    plane->Init();
}
票数 3
EN

Stack Overflow用户

发布于 2016-05-19 16:13:29

在C++中,类是(编译类型)定义,而不是(运行时)数据对象。所以你不能存储一个类。

但是,您可以声明一个工厂类型,并存储工厂的实例。

例如:

代码语言:javascript
复制
class Factory
{
     virtual std::unique_ptr<Object> createInstance(std::string description);
}

class CarFactory : public Factory
{
     std::unique_ptr<Object> createInstance(std::string description) override;
}
class PlaneFactory : public Factory
{
     std::unique_ptr<Object> createInstance(std::string description) override;
}

然后我们储存工厂:

代码语言:javascript
复制
std::map<const char[2],Factory*> factories = {
     {"00", new CarFactory},
     {"01", new PlaneFactory},
     //...
}

您可能可以创建一个通用工厂:

代码语言:javascript
复制
template<typename T>
class VehicleFactory : public Factory
{
     std::unique_ptr<Object> createInstance(std::string description) override
     { return std::make_unique<T>(description); }
}

std::map<int,Factory*> factories = {
     {"00", new VehicleFactory<Car>},
     {"01", new VehicleFactory<Plane>},
     //...
}

一旦我们有了工厂,我们就可以使用它:

代码语言:javascript
复制
std::unique_ptr<Object> createVehicle(const char type[2], std::string description)
{
    // error handling is an exercise for the reader
    return factories[type]->createInstance(description);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37328428

复制
相关文章

相似问题

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