我可以在 map<char[2],class> 中使用类类型作为容器吗?
Can I use class type in map<char[2],class> as container?
我想做的是:从XML文件加载数据(这很好)。XML告诉程序创建类实例(来自特定的不同类,如Car
或Plane
),然后这些实例将存在于程序中。这些类实例对象是总体Object
基类的子类。
XML文件以数字的形式存储需要创建的对象类型,程序将从中确定要创建的对象类别。
我可以使用switch
语句来枚举所有类型的对象,但在添加大量对象实例时,这会对性能造成极大的负担。因此,我想要一个从char[2]
到所需类的映射。(注意:对于类类型本身,而不是类的实例。)
例如,如果XML属性为'type=0x01'
,则将生成类Car
中的对象,而如果'type=0x02
',则将创建Plane
对象。(两者均为Object
)
通过这种方式,我想使用一个常量映射来完成这项工作。我想写一些类似的东西
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
这样做的目的是创建一种更快的方法,而不是坚持使用switch语句,这在创建数百个对象时非常糟糕。
我需要做什么才能从上面得到有效的C++?我不知道如何在映射中存储类类型。(我收到编译器错误,例如"参数2/4无效")
我不知道如何在映射中存储类类型。(我经常得到"参数2/4无效")
char[2]
数组不能用作std::map::key_type
,因为它不能满足Compare
概念的必要约束
从您的初始值设定项列表中,看起来您无论如何都希望uint8_t
作为键值。
此外,您不能将类型作为值存储在地图中。
如果你打算为构造函数使用函数指针,那是不可能的,因为构造函数和析构函数是特殊的野兽(没有返回类型,甚至连void
都没有),你不能用函数指针引用它们。
我认为您实际需要的是一个std::map
,它存储与enum
对应的工厂函数,如:
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(); } }
};
后一个映射初始化列表中的代码并不比您在(伪)代码示例中提供的代码多多少
如果你想摆脱锅炉板的东西,并且认为混淆代码是值得的,你仍然可以使用宏:
#define Create(classtype) []() { return new classtype(); }
std::map<VehicleTypes,CreateVehicleFn> CreatorFnList =
{ { VehicleTypes::CarType, Create(Car) } ,
{ VehicleTypes::PlaneType, Create(Plane) }
};
您可以稍后使用它根据关键参数创建新实例:
Plane* plane = dynamic_cast<Plane*>(CreateVehicleFn[VehicleTypes::PlaneType]());
if(plane) {
plane->Init();
}
为了提供清晰的所有权语义,甚至可以考虑使用std::unique_ptr<Vehicle>
将新实例从工厂传递到客户端:
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>(); } }
};
用法的语法与我的第一个示例的语法大致相同
std::unique_ptr<Plane> plane = CreateVehicleFn[VehicleTypes::PlaneType]();
if(plane.get()) {
plane->Init();
}
在C++中,类是(编译类型)定义,而不是(运行时)数据对象。所以你不能存储类。
但是,您可以声明工厂类型,并存储工厂的实例。
例如:
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;
}
然后我们储存工厂:
std::map<const char[2],Factory*> factories = {
{"00", new CarFactory},
{"01", new PlaneFactory},
//...
}
你也许可以制造一个通用工厂:
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>},
//...
}
一旦我们有了工厂,我们就可以使用它:
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);
}
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- C2011 'CMemDC':Visual Studio 2019中的'class'类型重新定义
- C++错误:"class name"之前的预期类型说明符
- "class":非法使用此类型作为表达式 如何解决?
- 如何配置 Doxygen 以在"Class Index"中包含类的类型定义?
- 无法将'Class::operator=='从"布尔"类型(类::)(类*)转换为"布尔"类型
- 获取生成错误:错误 C2011:'ProfileSettings':'class'类型重定义
- 'class MyClass' 在尝试定义静态结构实例时不会命名类型
- 'inherit class'中类型 'template class' 引用的初始化无效
- C++模板: <class> 不命名类型
- 无效使用不完整的类型"class..."
- 无效使用不完整的类型"class"
- 错误:返回类型 'class Polar' 不完整,无效使用类型 'polar'
- 无效使用不完整的类型'class QGraphicsRectItem'
- 无效使用不完整的类型'class...'
- 错误:请求“y”中的成员“x”,该成员属于非类类型“class**”
- 我收到错误"无效使用不完整的类型'class map'
- Qt - 无效使用不完整的类型 'class QScrollBar' - 为文本编辑小部件添加水平滚动条
- 如何确定作为void *返回的指针的类型(Class)
- 错误:无效使用了不完整的类型“class Theron::EndPoint”