提问者:小点点

将派生类对象存储在基类变量中


我想在一个向量中存储几个类的实例。 因为所有类都继承自同一个基类,所以这应该是可能的。

想象一下这个程序:

#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++的方法来做这件事。 并且我想要完全向量兼容(只是为了方便其他用户使用我的代码)。


共3个答案

匿名用户

您看到的是对象切片。
您将派生类的对象存储在向量中,该向量应该存储基类的对象,这导致对象切片,并且被存储的对象的派生类特定成员被切片,因此存储在向量中的对象只是充当基类的对象。

解决方案:

您应该在向量中存储指向基类对象的指针:

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;
};