将派生类对象存储在基类变量中
我想在向量中存储几个类的实例。由于所有类都继承自同一个基类,这应该是可能的。
想象一下这个程序:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual void identify ()
{
cout << "BASE" << endl;
}
};
class Derived: public Base
{
public:
virtual void identify ()
{
cout << "DERIVED" << endl;
}
};
int main ()
{
Derived derived;
vector<Base> vect;
vect.push_back(derived);
vect[0].identify();
return 0;
}
我希望它打印 "DERIVED"
,因为 identify()
方法是虚拟
。相反,vect[0]
似乎是一个 Base
实例,并且它打印 "BASE"
。
我想我可以编写自己的容器(可能源自vector
),它能够以某种方式做到这一点(也许只保存指针......)。
我只是想问是否有更 C++ 的方式来做到这一点。而且我希望完全兼容矢量(只是为了方便其他用户使用我的代码)。
I would like to store instances of several classes in a vector. Since all classes inherit from the same base class this should be possible.
Imagine this program:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual void identify ()
{
cout << "BASE" << endl;
}
};
class Derived: public Base
{
public:
virtual void identify ()
{
cout << "DERIVED" << endl;
}
};
int main ()
{
Derived derived;
vector<Base> vect;
vect.push_back(derived);
vect[0].identify();
return 0;
}
I expected it to print "DERIVED"
, because the identify()
method is virtual
. Instead vect[0]
seems to be a Base
instance and it prints "BASE"
.
I guess I could write my own container (probably derived from vector
) somehow that is capable of doing this (maybe holding only pointers...).
I just wanted to ask if there is a more C++'ish way to do this. AND I would like to be completely vector
-compatible (just for convenience if other users should ever use my code).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我会使用
vector
来存储它们。如果你说vector
,就会发生切片。这确实意味着在从向量中删除指针后,您必须自己删除实际对象,但否则应该没问题。
I'd use
vector<Base*>
to store them. If you sayvector<Base>
, slicing will occur.This does mean that you'd have to delete the actual objects yourself after you've removed the pointers from your vector, but otherwise you should be fine.
正如这里提到的所有其他人一样,由于复制构造时会发生对象切片,因此您无法完成将派生对象插入基向量。
如果目标是避免内存分配,您可以使用
std::variant
,但向量将不再属于 base 类As all others mentioned here, you cannot accomplish to insert an object of derived to a vector of base due to object slicing that would happen on copy construction.
If goal is to avoid memory allocation, you can use an
std::variant
, but the vector would no longer be of base class您所看到的是对象切片。
您将派生类的对象存储在一个向量中,该向量应该存储基类的对象,这会导致对象切片,并且所存储的对象的派生类特定成员被切片,因此存储在向量中的对象仅充当基类的对象。
解决方案:
您应该在向量中存储指向基类对象的指针:
通过存储指向基类的指针,就不会进行切片,并且您也可以实现所需的多态行为。
由于您要求使用 C++ 方式来执行此操作,因此正确的方法是使用合适的 智能指针而不是在向量中存储原始指针。这将确保您不必手动管理内存,RAII会自动为你做这件事。
What you are seeing is Object Slicing.
You are storing object of Derived class in an vector which is supposed to store objects of Base class, this leads to Object slicing and the derived class specific members of the object being stored get sliced off, thus the object stored in the vector just acts as object of Base class.
Solution:
You should store pointer to object of Base class in the vector:
By storing a pointer to Base class there would be no slicing and you can achieve the desired polymorphic behavior as well.
Since you ask for a
C++ish
way of doing this, the right approach is to use a suitable Smart pointer instead of storing a raw pointer in the vector. That will ensure you do not have to manually manage the memory, RAII will do that for you automatically.你正在经历切片。向量复制
衍生
对象,插入一个新的Base
类型。You're experiencing slicing. The vector copies the
derived
object, a new one of typeBase
is inserted.TL;DR:您不应该从公共可复制/可移动类继承。
实际上可以在编译时防止对象切片:在此上下文中基对象不应该是可复制的。
情况 1:抽象基
如果基是抽象的,则无法实例化,因此无法体验切片。
情况 2:具体基础
如果基础不是抽象的,则可以复制它(默认情况下)。您有两种选择:
注意:在 C++11 中,移动操作会导致相同的问题。
TL;DR: You should not inherit from a publicly copyable/movable class.
It is actually possible to prevent object slicing, at compilation time: the base object should not be copyable in this context.
Case 1: an abstract base
If the base is abstract, then it cannot be instantiated and thus you cannot experience slicing.
Case 2: a concrete base
If the base is not abstract, then it can be copied (by default). You have two choices:
Note: in C++11, the move operations cause the same issue.