模板中的多态类
假设我们有一个类层次结构,其中有一个通用 Animal
类,该类有几个直接继承自它的类(例如 Dog
、Cat
、马
等)。
在此继承层次结构上使用模板时,仅使用 SomeTemplateClass
然后将 Dogs、Cats 和 Horses 推入此模板化对象是否合法?
例如,假设我们有一个模板化的 Stack 类,我们想要在其中托管各种动物。我可以简单地说一下Stack
Let's say we have a class hierarchy where we have a generic Animal
class, which has several classes directly inherit from it (such as Dog
, Cat
, Horse
, etc..).
When using templates on this inheritance hierarchy, is it legal to just use SomeTemplateClass<Animal>
and then shove in Dogs and Cats and Horses into this templated object?
For example, assume we have a templated Stack
class, where we want to host all sorts of animals. Can I simply state Stack<Animal> s; Dog d; s.push(d); Cat c; s.push(c);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果否,则回答您的问题。但是您可以使用
SomeTemplateClass
并将派生类对象的指针传递给它。例如,如果您有一个模板化的 Stack 类,您想要在其中托管各种动物。您可以简单地执行以下操作:
Answer of your question if No. But you can use
SomeTemplateClass<Animal*>
and pass pointers of objects of derived classes to it.For example, if you have a templated Stack class, where you want to host all sorts of animals. You can simply do following:
不,您必须使用指针,即 Stack(或某种智能指针)。原因是
Dog
、Cat
、Horse
等大小不一定相同,因为它们可能会添加成员变量。容器可以分配仅足以存储
动物
的空间。如果Dog
大于该值,容器将尝试复制构造一个Dog
,并将其推入太小的空间中,从而可能导致内存损坏。No, you'd have to use pointers, i.e.
Stack<Animal*>
(or some kind of smart pointer). The reason is thatDog
,Cat
,Horse
etc. are not necessarily the same size, since they might add member variables.The container may allocate space that is only large enough to store an
Animal
. If aDog
is larger than that, the container will try to copy-construct aDog
that is pushed into it in too small a space, potentially causing memory corruption.Stack
和Stack
是完全不同的类。您甚至无法在
Stack
和Stack
之间进行转换。编辑:但正如 @Mihran 指出的,您可以尝试使用
Stack
代替Stack
NO
Stack<Animal>
andStack<Dog>
are completely different classes.You can't even cast between
Stack<Animal>
andStack<const Animal>
.Edit: But as @Mihran pointed you can try to use
Stack<Animal* >
insteadStack<Animal>
这取决于模板对传递的类型的用途。如果您指的是标准容器(例如
std::vector
、std::map
等),那么答案是否定的。即使在您的类层次结构中,狗派生自动物,std::vector和
std::vector
之间也没有任何关系。您不能将
Dog
放入std::vector
...C++ 使用复制语义,您会遇到所谓的“切片”,这意味着您的Dog
实例将丢失任何不存在于Animal
基类中的成员。然而,一般来说,模板当然很可能以不同的方式使用该类型,从而允许接受派生类的实例。例如,在以下代码中,模板
MethodCaller
可以使用类型实例化,但使用派生类型的实例并正确处理后期绑定分派。这是可能的,因为MethodCaller
实例仅保存引用并且不复制该对象。也可以根据需要实现 Stack 类...
请注意,在实现中我使用了 std::vector 来保存指针/strong> 对动物来说,因此可以避免切片问题。我一直在使用模板方法来接受推送调用中的派生类型。
另请注意,在弹出动物时,您必须提供类是什么以及是否是错误的类(例如,当堆栈顶部元素是
Dog
时,您弹出Crocodile
) )你会在运行时得到一个bad_cast
异常。It depends on what use the template does with the passed type. If you mean standard containers (e.g.
std::vector
,std::map
and so on) then the answer is no. There is no relation at all betweenstd::vector<Animal>
andstd::vector<Dog>
even if in your class hierarchy dogs derive from animals.You cannot put a
Dog
in anstd::vector<Animal>
... C++ uses copy semantic and you would incur in what is called "slicing" that means that yourDog
instance will lose any member that is not also present in the baseAnimal
class.However in general it's of course well possible for a template to use the type in different ways that will allow therefore accept instances of derived classes. For example in the following code the template
MethodCaller
can be instantiated with a type but using an instance of a derived type and correctly handling late binding dispatch. This is possible because theMethodCaller
instance only holds a reference and doesn't make a copy of the object.It is also possible to implement the
Stack
class as you want...Note that in the implementation I've used an
std::vector
for keeping pointers to animals and therefore to avoid the slicing problem. I've been using a template method to be able to accept derived types in the push call.Also note that when popping animals you must provide what is the class and if it's a wrong one (e.g. you pop out a
Crocodile
when the top element on the stack is aDog
) you will get abad_cast
exception at runtime.