将派生类对象存储在基类variables中
我想将几个类的实例存储在一个向量中。 由于所有的类都从同一个基类inheritance,所以这应该是可能的。
想象一下这个程序:
#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; }
我期望它打印“派生”,因为“识别”方法是虚拟的。 相反,“vect [0]”似乎是一个“基础”的实例,它打印
基础
我想我可以编写我自己的容器(可能来自vector),不知何故,这是能够做到这一点(也许只有指针…)。 我只想问是否有更多的C ++ ish方法来做到这一点。 我想完全向量兼容(只是为了方便,如果其他用户应该使用我的代码)。
你看到的是对象切片 。
您正在将Derived类的对象存储在一个应该存储Base类对象的向量中,这导致了Object切片,并且被存储的对象的派生类特定成员被切掉,因此存储在该向量中的对象只是作为基类的对象。
解:
你应该在vector中存储指向Base类对象的指针:
vector<Base*>
通过存储一个指向Base类的指针,就不会出现切片,而且您也可以实现所需的多态行为。
既然你要求C++ish
是这样做的,正确的方法是使用一个合适的智能指针,而不是将原始指针存储在向量中。 这将确保您不必手动pipe理内存, RAII将自动为您执行此操作。
你正在经历切片。 vector复制derived
对象,插入一个新的Base
types。
TL; DR:你不应该从公开的复制/移动类inheritance。
实际上,可以在编译时防止对象切片:在此上下文中,基础对象不应该是可复制的。
案例1:一个抽象的基础
如果基础是抽象的,那么它不能被实例化,因此你不能体验切片。
案例2:一个具体的基地
如果基地不是抽象的,那么它可以被复制(默认)。 你有两个select:
- 完全防止复制
- 只允许儿童复制
注意:在C ++ 11中,移动操作会导致相同的问题。
// C++ 03, prevent copy class Base { public: private: Base(Base const&); void operator=(Base const&); }; // C++ 03, allow copy only for children class Base { public: protected: Base(Base const& other) { ... } Base& operator=(Base const& other) { ...; return *this; } }; // C++ 11, prevent copy & move class Base { public: Base(Base&&) = delete; Base(Base const&) = delete; Base& operator=(Base) = delete; }; // C++ 11, allow copy & move only for children class Base { public: protected: Base(Base&&) = default; Base(Base const&) = default; Base& operator=(Base) = default; };
我会使用vector<Base*>
来存储它们。 如果你说vector<Base>
,切片就会发生。
这意味着你必须删除实际的对象后,你已经删除了向量的指针,但否则你应该没问题。