首页 文章

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

提问于
浏览
45

我想在向量中存储几个类的实例 . 由于所有类都继承自相同的基类,因此这是可能的 .

想象一下这个程序:

#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”,因为“识别”方法是虚拟的 . 相反,'vect [0]'似乎是一个'Base'实例,它打印出来

BASE

我想我可以写一个我自己的容器(可能是从vector派生的),不知何故能够做到这一点(也许只能拿指针......) . 我只是想问一下是否有更多的C ish方法来做到这一点 . 我希望完全兼容矢量(只是为了方便其他用户应该使用我的代码) .

4 回答

  • 54

    你所看到的是 Object Slicing .
    您将Derived类的对象存储在一个向量中,该向量应该存储Base类的对象,这会导致对象切片,并且被存储的对象的派生类特定成员被切掉,因此存储在向量中的对象就像基类的对象 .

    Solution:

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

    vector<Base*>
    

    通过存储指向Base类的指针,就没有切片,你也可以实现所需的多态行为 .
    由于你要求这样做的方法,正确的方法是使用合适的 Smart pointer 而不是在向量中存储原始指针 . 这将确保您不必手动管理内存, RAII 将自动为您执行此操作 .

  • 5

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

  • 5

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


    实际上,在编译时可以防止对象切片:在此上下文中,基础对象不应该是可复制的 .

    案例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;
    };
    
  • 2

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

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

相关问题