Store derived class objects in base class variables
我想在一个向量中存储几个类的实例。因为所有类都继承自同一个基类,所以这应该是可能的。
想象一下这个程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #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
我想我可以写我自己的容器(可能是从向量派生的),以某种方式能够做到这一点(可能只包含指针…)。我只是想问一下,是否有更多的C++ ISH方法来做这件事。我希望完全与向量兼容(只是为了方便其他用户使用我的代码)。
你看到的是物体切片。您将派生类的对象存储在一个向量中,这个向量应该存储基类的对象,这将导致对象切片,并且被存储的对象的派生类特定成员被切掉,因此存储在向量中的对象只是作为基类的对象。
解决方案:
您应该将指向基类对象的指针存储在向量中:
1 | vector<Base*> |
通过存储指向基类的指针,就不会有切片,您也可以实现所需的多态行为。由于您要求使用
tl;dr:您不应该从可公开复制/可移动类继承。
实际上,在编译时可以防止对象切片:在此上下文中,基对象不应是可复制的。
案例1:抽象基础
如果基是抽象的,那么它就不能被实例化,因此您不能体验到切片。
案例2:混凝土基础
如果基不是抽象的,那么可以复制它(默认情况下)。您有两个选择:
- 完全禁止复制
- 仅允许儿童复制
注意:在C++ 11中,移动操作会导致相同的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // 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; }; |
你正在经历切片。矢量复制了
我会用
这意味着在从向量中删除指针之后,必须自己删除实际的对象,否则就可以了。