关于c ++:将派生类对象存储在基类变量中

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*>

通过存储指向基类的指针,就不会有切片,您也可以实现所需的多态行为。由于您要求使用C++ish方法来完成此操作,正确的方法是使用合适的智能指针,而不是将原始指针存储在向量中。这将确保您不必手动管理内存,RAII将自动为您管理内存。


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


你正在经历切片。矢量复制了derived对象,插入了Base类型的新对象。


我会用vector来储存它们。如果你说vector,就会发生切片。

这意味着在从向量中删除指针之后,必须自己删除实际的对象,否则就可以了。