从动态类型信息创建新对象
在C++中,有没有办法查询对象的类型,然后使用该信息动态创建相同类型的新对象?
例如,假设我有一个简单的 3 类层次结构:
class Base
class Foo : public Base
class Bar : public Base
现在假设我给你一个转换为 Base 类型的对象——它实际上是 Foo 类型。 有没有办法查询类型并使用该信息稍后创建 Foo 类型的新对象?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
克隆方法
语言没有提供任何查询类型并让您根据该信息进行构造的功能,但是您可以通过各种方式为类层次结构提供功能,其中最简单的是使用虚拟方法:
这会做一些稍微不同的事情:克隆当前对象。这通常是您想要的,并且允许您将对象保留为模板,然后您可以根据需要克隆和修改它们。
扩展Tronic,您甚至可以< a href="http://bitbucket.org/kniht/scraps/src/tip/cpp/clone.hpp" rel="nofollow noreferrer">生成 克隆函数。
为什么auto_ptr?因此,您可以使用new来分配对象,使所有权的转移明确,并且调用者毫无疑问delete必须释放它。例如:
对象工厂
如果您希望完全按照您的要求进行操作并获得一个可以独立于实例使用的工厂:
可以将许多相同的逻辑和功能用于克隆方法,如 get_factory /em> 完成一半相同的角色,返回类型(及其含义)是唯一的区别。
我还介绍了工厂夫妇 已经多次了。您可以调整我的 SimpleFactory 类 所以您的工厂对象(返回by get_factory)持有对全局工厂的引用以及要传递以创建的参数(例如类的注册名称 - 考虑如何应用 boost::function 和 boost::bind 使其易于使用)。
Clone method
There is nothing provided by the language that queries type and lets you construct from that information, but you can provide the capability for your class hierarchy in various ways, the easiest of which is to use a virtual method:
This does something slightly different: clone the current object. This is often what you want, and allows you to keep objects around as templates, which you then clone and modify as desired.
Expanding on Tronic, you can even generate the clone function.
Why auto_ptr? So you can use new to allocate the object, make the transfer of ownership explicit, and the caller has no doubt that delete must deallocate it. For example:
Object factory
If you'd prefer to do exactly as you asked and get a factory that can be used independently of instances:
Much of the same logic and functionality can be used as for a clone method, as get_factory fulfills half of the same role, and the return type (and its meaning) is the only difference.
I've also covered factories a couple times already. You could adapt my SimpleFactory class so your factory object (returned by get_factory) held a reference to a global factory plus the parameters to pass to create (e.g. the class's registered name—consider how to apply boost::function and boost::bind to make this easy to use).
通过基类创建对象副本的常用方法是添加clone方法,它本质上是一个多态复制构造函数。此虚拟函数通常需要在每个派生类中定义,但您可以通过使用 奇怪的重复模板模式:
请注意,您可以将相同的 CRTP 类用于每个派生类中相同但需要了解派生类型的任何功能。除了clone()之外,它还有许多其他用途,例如双重调度。
The commonly used way to create copies of objects by base class is adding a clone method, which is essentially a polymorphic copy constructor. This virtual function normally needs to be defined in every derived class, but you can avoid some copy&paste by using the Curiously Recurring Template Pattern:
Notice that you can use the same CRTP class for any functionality that would be the same in every derived class but that requires knowledge of the derived type. There are many other uses for this besides clone(), e.g. double dispatch.
只有一些古怪的方法可以做到这一点。
第一个,恕我直言,最丑陋的是:
请注意,只有在启用了 RTTI 并且 Base 包含一些虚拟功能时,这才有效。
第二个更简洁的版本是向基类添加纯虚拟克隆函数,
这更简洁。
一件很酷/有趣的事情是
Foo::clone
返回Foo*
,而Bar::clone
返回Bar*
。您可能期望这会破坏一些东西,但是由于 C++ 的一个称为协变返回类型的功能,一切都可以正常工作。不幸的是,协变返回类型不适用于智能指针,因此使用
shared_ptrs
您的代码将如下所示。There's only some hacky ways to do this.
The first and IMHO the ugliest is:
Note that this will only work if you have RTTI enabled and Base contains some virtual function.
The second an neater version is to add a pure virtual clone function to the base class
This is much neater.
One cool/interesting thing about this is that
Foo::clone
returns aFoo*
, whileBar::clone
returns aBar*
. You might expect this to break things, but everything works due to a feature of C++ called covariant return types.Unfortunately covariant return types don't work for smart pointers, so using
sharted_ptrs
your code would look like this.您可以使用例如
typeid
来查询对象的动态类型,但我不知道如何从类型信息直接实例化新对象。但是,除了上面提到的
clone
方法之外,您还可以使用工厂:PS:此代码示例的基本部分当然是
Factory::createFrom方法。 (这可能不是最漂亮的 C++ 代码,因为我的 C++ 已经有点生疏了。再想一想,工厂方法可能不应该是静态的。)
You can use e.g.
typeid
to query an object's dynamic type, but I don't know of a way to directly instantiate a new object from the type information.However, apart from the
clone
approach mentioned above, you could use a factory:P.S.: The essential part of this code example is of course the
Factory::createFrom
method. (It's probably not the most beautiful C++ code, since my C++ has gone a little rusty. The factory method probably shouldn't be static, on second thought.)我在项目中使用宏来综合此类方法。
我现在正在研究这种方法,所以我可能是错的,但这是我的 IAllocable.hh 代码中对您问题的答案。请注意,我使用 GCC 4.8,但我希望 4.7 适合。
使用方法:
希望有帮助。
I used macros in my project to synthesize such methods.
I'm just researching this approach now, so I may be wrong, but here's an answer to your question in my code of IAllocable.hh. Note that I use GCC 4.8, but I hope 4.7 suits.
Usage:
Hope it helps.
是的,使用
typeid()
运算符例如:
输出:
如果typeid评估的类型是a指针前面带有解引用运算符 (*),并且该指针具有空值,typeid 会抛出 bad_typeid 异常
阅读 更多......
Yes, use
typeid()
operatorFor example:
Output:
If the type typeid evaluates is a pointer preceded by the dereference operator (*), and this pointer has a null value, typeid throws a bad_typeid exception
Read more.....
当有极多的类派生自同一个基类时,此代码将使您不必在每个类中包含克隆方法。这是一种更方便的克隆方法,涉及模板和中间子类。如果层次结构足够浅,这是可行的。
When there are extremely many classes deriving from the same base class then this code will save you from having to include clone methods every class. It's a more convenient way of cloning that involves templates and an intermediate subclass. It's doable if the hierarchy is shallow enough.