我想在一个向量中存储几个类的实例。 因为所有类都继承自同一个基类,所以这应该是可能的。
想象一下这个程序:
#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”实例,它将打印
基地
我想我可以用某种方式编写自己的容器(可能是从vector派生的),它能够做到这一点(可能只包含指针。。。)。 我只是想问一下,是否有一个更适合C++的方法来做这件事。 并且我想要完全向量兼容(只是为了方便其他用户使用我的代码)。
您看到的是对象切片。
您将派生类的对象存储在向量中,该向量应该存储基类的对象,这导致对象切片,并且被存储的对象的派生类特定成员被切片,因此存储在向量中的对象只是充当基类的对象。
解决方案:
您应该在向量中存储指向基类对象的指针:
vector<Base*>
通过存储指向基类的指针,将不存在切片,并且您还可以实现所需的多态行为。
由于您要求使用C++ISH
方式来实现此操作,正确的方法是使用合适的智能指针,而不是在向量中存储原始指针。 这将确保您不必手动管理内存,RAII将自动为您执行此操作。
你正在经历切片。 向量复制派生的
对象,并插入一个类型为base
的新对象。
您不应该继承一个可公开复制/可移动的类。
实际上,在编译时可以防止对象切片:在此上下文中,基对象不应该是可复制的。
案例1:抽象基础
如果基是抽象的,那么它就无法实例化,因此您无法体验切片。
案例2:混凝土底座
如果基不是抽象的,那么它可以被复制(默认情况下)。 您有两个选择:
注意:在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;
};