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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8777724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:05:46  来源:igfitidea点击:

Store derived class objects in base class variables

c++polymorphismobject-slicing

提问by drakide

I would like to store instances of several classes in a vector. Since all classes inherit from the same base class this should be possible.

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

Imagine this program:

想象一下这个程序:

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

I expected it to print "DERIVED", because the "identify" method is virtual. Instead 'vect[0]' seems to be a 'Base' instance and it prints

我希望它打印“DERIVED”,因为“identify”方法是虚拟的。相反 'vect[0]' 似乎是一个 'Base' 实例,它打印

BASE

根据

I guess I could write my own container (probably derived from vector) somehow that is capable of doing this (maybe holding only pointers...). I just wanted to ask if there is a more C++ish method for doing this. AND I would like to be completely vector-compatible (just for convenience if other users should ever use my code).

我想我可以以某种方式编写自己的容器(可能源自向量),以某种方式能够做到这一点(也许只保存指针......)。我只是想问一下是否有更多的 C++ish 方法来做到这一点。而且我希望完全兼容矢量(只是为了方便,如果其他用户应该使用我的代码)。

回答by Alok Save

What you are seeing is Object Slicing.
You are storing object of Derived class in an vector which is supposed to store objects of Base class, this leads to Object slicing and the derived class specific members of the object being stored get sliced off, thus the object stored in the vector just acts as object of Base class.

你看到的是Object Slicing
您将派生类的对象存储在一个应该存储基类对象的向量中,这会导致对象切片,并且存储的对象的派生类特定成员被切片,因此存储在向量中的对象只是作为基类的对象。

Solution:

解决方案:

You should store pointer to object of Base class in the vector:

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

vector<Base*> 

By storing a pointer to Base class there would be no slicing and you can achieve the desired polymorphic behavior as well.
Since you ask for a C++ishway of doing this, the right approach is to use a suitable Smart pointerinstead of storing a raw pointer in the vector. That will ensure you do not have to manually manage the memory, RAIIwill do that for you automatically.

通过存储指向 Base 类的指针,将不会进行切片,您也可以实现所需的多态行为。
既然您要求C++ish这样做,正确的方法是使用合适的智能指针,而不是在向量中存储原始指针。这将确保您不必手动管理内存,RAII会自动为您管理。

回答by Andre

You're experiencing slicing. The vector copies the derivedobject, a new one of type Baseis inserted.

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

回答by Matthieu M.

TL;DR: You should not inherit from a publicly copyable/movable class.

TL;DR:您不应该从公共可复制/可移动类继承。



It is actually possible to prevent object slicing, at compilation time: the base object should not be copyable in this context.

实际上可以在编译时防止对象切片:在这种情况下,基础对象不应该是可复制的。

Case 1: an abstract base

案例 1:抽象基础

If the base is abstract, then it cannot be instantiated and thus you cannot experience slicing.

如果基础是抽象的,那么它不能被实例化,因此你不能体验切片。

Case 2: a concrete base

案例2:混凝土基础

If the base is not abstract, then it can be copied (by default). You have two choices:

如果基础不是抽象的,那么它可以被复制(默认情况下)。你有两个选择:

  • prevent copy altogether
  • allow copy only for children
  • 完全防止复制
  • 仅允许儿童复制

Note: in C++11, the move operations cause the same issue.

注意:在 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;
};

回答by Vlad

I'd use vector<Base*>to store them. If you say vector<Base>, slicing will occur.

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

This does mean that you'd have to delete the actual objects yourself after you've removed the pointers from your vector, but otherwise you should be fine.

这确实意味着您必须在从向量中删除指针后自己删除实际对象,否则您应该没问题。

回答by Van Tran

// Below is the solution by using vector<Based*> vect,
// Base *pBase , and initialized pBase with
// with the address of derived which is
// of type Derived

#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 ()

{
Base *pBase; // The pointer pBase of type " pointer to Base"
Derived derived;
// PBase is initialized with the address of derived which is
// of type Derived

pBase = & derived;
// Store pointer to object of Base class in the vector:
vector<Base*> vect;
// Add an element to vect using pBase which is initialized with the address 
// of derived
vect.push_back(pBase);
vect[0]->identify();
return 0;
}