通过名称创建对象
是否可以使用 C++ 中传递的类型名称(字符串)返回对象的示例? 我有一些基本抽象类 Base
和一些派生类。示例代码:
class Base
{
/* ... */
};
class Der1 : public Base
{
/* ... */
};
class Der2 : public Base
{
/* ... */
};
我需要这样的函数:
Base *objectByType(const std::string &name);
派生类的数量是可变的,我不想进行类似切换 name
并手动返回新对象类型的操作。无论如何,在 C++ 中是否可以自动执行此操作?
ps 用法应该如下所示:
dynamic_cast<Der1>(objectByType("Der1"));
我需要纯 C++ 代码(跨平台)。使用升压是允许的。
is it possible to return exemplar of object using passed type name (string) in c++?
I have some base abstract class Base
and a few derivates. Example code:
class Base
{
/* ... */
};
class Der1 : public Base
{
/* ... */
};
class Der2 : public Base
{
/* ... */
};
And I need function like:
Base *objectByType(const std::string &name);
Number of derivates classes are changeable and I don't want to make something like switching of name
and returning by hands new object type. Is it possible in c++ to do that automatically anyway?
p.s. usage should looks like:
dynamic_cast<Der1>(objectByType("Der1"));
I need pure c++ code (crossplatform). Using boost is permissible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有一个很好的技巧,可以让你编写一个没有
if 序列的 工厂方法 ...否则如果...
。(请注意,AFAIK,确实不可能在 C++ 中执行您想要的操作,因为此代码是在编译时生成的。“工厂方法”设计模式就是为此目的而存在的)
首先,为派生类定义一个
全局存储库
。它可以采用std::map
的形式,即将派生类的名称映射到该类的实例
。对于每个派生类,您定义一个
默认构造函数
,它将该类的对象添加到类名称下的存储库中。您还定义了该类的静态实例:静态变量的构造函数甚至在
main()
之前运行,因此当您的main
启动时,您已经使用以下实例初始化了存储库所有派生类。您的工厂方法(例如
Base::getObject(const std::string&)
)需要在存储库映射中搜索类名。然后,它使用找到的对象的clone()
方法来获取相同类型的新对象。您当然需要为每个子类实现clone
。这种方法的优点是,当您添加新的派生类时,您的添加仅限于实现新类的文件。存储库和工厂代码不会改变。当然,您仍然需要重新编译您的程序。
There is a nice trick which allows you to write a factory method without a sequence of
if...else if...
.(note that, AFAIK, it is indeed not possible to do what you want in C++ as this code is generated in the compile time. A "Factory Method" Design Pattern exists for this purpose)
First, you define a
global repository
for your derived classes. It can be in the formstd::map<std::string, Base*>
, i.e. maps a name of the derived class toan instance
of that class.For each derived class you define a
default constructor
which adds an object of that class to the repository under class's name. You also define a static instance of the class:Constructors of static variables are run even before
main()
, so when yourmain
starts you already have the repository initialized with instances of all derived classes.Your factory method (e.g.
Base::getObject(const std::string&)
) needs to search the repository map for the class name. It then uses theclone()
method of the object it finds to get a new object of the same type. You of course need to implementclone
for each subclass.The advantage of this approach is that when you are adding a new derived class your additions are restricted only to the file(s) implementing the new class. The repository and the factory code will not change. You will still need to recompile your program, of course.
在 C++ 中不可能做到这一点。
一种选择是编写一个工厂并打开传入的名称,但我发现您不想这样做。除了dynamic_cast之外,C++不提供任何真正的运行时反射支持,因此此类问题很难解决。
It's not possible to do this in C++.
One options is to write a factory and switch on the name passed in, but I see you don't want to do that. C++ doesn't provide any real runtime reflection support beyond dynamic_cast, so this type of problem is tough to solve.
是的,这是可能的!检查这个非常有趣的类,名为 <代码>激活器
您可以通过
Type
和string
创建所有内容,甚至可以给出参数列表,因此该方法将使用最佳参数集调用适当的构造函数。Yes that is possible! Check this very funny class called
Activator
You can create everything by
Type
andstring
and can even give a List of parameters, so the method will call the appropriate constructor with the best set of arguments.这是不可能的。您必须自己编写
objectByType
函数:It is not possible. You have to write the
objectByType
function yourself:C++ 不支持反射。
在我看来,这是 Java 击败 C++ 的一点。
(希望不要为此获得太多反对票...)
您可以通过使用自定义预处理器来实现类似的目标,类似于 MOC 对 Qt 的做法。
C++ doesn't support reflection.
In my opinion this is the single point where Java beats C++.
(ope not to get too many down votes for this...)
You could achieve something like that by using a custom preprocessor, similar to how MOC does for Qt.