通常,如果您事先知道要创建的所有类型,则可以执行以下操作:
typedef enum{
BASE_CREATURE_TYPE = 0,
ANIMAL_CREATURE_TYPE,
...
}CREATURE_TYPES
但这变得乏味,因为每次创建新类时,都需要更新枚举。另外,CREATURE_TYPES仍然只是枚举中的项目-如何绑定(bind)到实际的类?
我想知道是否可以通过某种方式编写类,并且在运行时无需实际实例化对象即可创建包含所有类型的集合。
这在C++中可能吗?在Java中,有一种称为“静态块”的东西,当JVM加载该类时会执行这些东西。
编辑:这个问题不是关于静态块-只是一个例子-我想知道是否有某种方式,我可以执行一个方法或代码块,以便我知道什么类在运行时存在,而无需实际创建对象
编辑:我的意思是所有类型的集合,而不是“ map ”,因此我可以创建每种类型的对象,而不必维护列表。
编辑:我想要这个的原因是因为我试图创建一个函数,该函数可以在作为应用程序一部分的所有派生类上调用方法。例如,假设我有几个类都从Foo类派生,并具有一个balls():
Foo{
balls();
}
Boo : public Foo{
balls();
}
Coo: public Foo{
balls():
}
在运行时,我想了解所有派生类,因此我可以调用:
DerivedClass:balls();
编辑:请注意,我不需要了解每个派生类的所有成员,我只想知道所有派生类是什么,因此我可以对它们中的每一个调用balls()。
编辑:这个问题是相似的:How to automatically register a class on creation
但不幸的是,他正在存储一个std::string()。一个人如何指代实际的类(class)呢?
编辑:在下面的Smeehey的答案中,在main方法中,我将如何实际创建每个类的实例,并同时调用静态和非静态方法?
最佳答案
您可以为所有类创建一个静态注册表,并使用几个帮助程序宏在其中注册新类型。下面是一个基本的工作演示,它从Base创建2个派生类。要添加新的类,您只需使用显示的两个宏-一个在类内,一个在类外。注意:该示例是非常简单的,并不涉及检查重复项或其他错误条件之类的事情以最大程度地提高清晰度。
class BaseClass
{
};
class Registry
{
public:
static void registerClass(const std::string& name, BaseClass* prototype)
{
registry[name] = prototype;
}
static const std::map<std::string, BaseClass*>& getRegistry() { return registry; };
private:
static std::map<std::string, BaseClass*> registry;
};
std::map<std::string, BaseClass*> Registry::registry;
#define REGISTER_CLASS(ClassType) static int initProtoType() { static ClassType proto; Registry::registerClass(std::string(#ClassType), &proto); return 0; } static const int regToken;
#define DEFINE_REG_CLASS(ClassType) const int ClassType::regToken = ClassType::initProtoType();
class Instance : public BaseClass
{
REGISTER_CLASS(Instance)
};
DEFINE_REG_CLASS(Instance)
class OtherInstance : public BaseClass
{
REGISTER_CLASS(OtherInstance)
};
DEFINE_REG_CLASS(OtherInstance)
int main()
{
for(auto entry : Registry::getRegistry())
{
std::cout << entry.first << std::endl;
}
return 0;
}
上面注册了派生类的原型(prototype),这些原型(prototype)可以用于例如复制构造其他实例。或者,根据OP的要求,您可以拥有一个注册工厂方法而不是原型(prototype)的系统。这使您可以使用具有任何特定签名的构造函数(而不是复制构造函数)创建实例:
class BaseClass
{
};
class Registry
{
public:
using factoryMethod = BaseClass* (*)(int a, int b, int c);
static void registerClass(const std::string& name, factoryMethod meth)
{
registry[name] = meth;
}
static BaseClass* createInstance(const std::string& type, int a, int b, int c)
{
return registry[type](a, b, c);
}
static const std::map<std::string, factoryMethod>& getRegistry() { return registry; };
private:
static std::map<std::string, factoryMethod> registry;
};
std::map<std::string, Registry::factoryMethod> Registry::registry;
#define REGISTER_CLASS(ClassType) static BaseClass* createInstance(int a, int b, int c) \
{ \
return new ClassType(a,b,c); \
} \
static int initRegistry() \
{ \
Registry::registerClass( \
std::string(#ClassType), \
ClassType::createInstance); \
return 0; \
} \
static const int regToken; \
#define DEFINE_REG_CLASS(ClassType) const int ClassType::regToken = ClassType::initRegistry();
class Instance : public BaseClass
{
Instance(int a, int b, int c){}
REGISTER_CLASS(Instance)
};
DEFINE_REG_CLASS(Instance)
class OtherInstance : public BaseClass
{
OtherInstance(int a, int b, int c){}
REGISTER_CLASS(OtherInstance)
};
DEFINE_REG_CLASS(OtherInstance)
int main()
{
std::vector<BaseClass*> objects;
for(auto entry : Registry::getRegistry())
{
std::cout << entry.first << std::endl;
objects.push_back(Registry::createInstance(entry.first, 1, 2, 3));
}
return 0;
}
关于c++ - 一个人如何设计一个基类,以便在运行时知道所有的 "derived"类?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37746879/