在基类类型的向量中保存的基对象和派生对象被切片

Posted

技术标签:

【中文标题】在基类类型的向量中保存的基对象和派生对象被切片【英文标题】:Base and derived objects held in vector of base class type get sliced 【发布时间】:2021-09-05 01:36:37 【问题描述】:

所以我刚刚学习了矢量模板的基础知识,我正在尝试制作一个同时包含 Base 对象和 Derived 对象类的矢量。但是派生对象会被切片(仅打印 baseVariable,尽管它也应该打印 DerivedVariable。所以我有两个问题,首先: 是否在此处正确完成了使用用户输入创建新对象?我可以让它更好或更短吗?

Base* ptr = new Base();
            cin >> *ptr;
            vec.push_back(unique_ptr<Base>(ptr));

为什么派生对象会被切片?

class Base

protected:
    string baseVariable_;
public:
    void display() 
        cout << "BaseVar: " << baseVariable_ << endl;
    
    friend istream& operator>>(istream& in, Base& obj);

;
istream& operator>>(istream& in, Base& obj)

    in >> obj.baseVariable_;
    return in;




class Derived :public Base

public: //public just for test
    string derivedVariable_;
    void display() 
        Base::display();
        cout << "DerivedVar: " << derivedVariable_ << endl;
    
    friend istream& operator>>(istream& in, Derived& obj);
;
istream& operator>>(istream& in, Derived& obj)

    in >> obj.baseVariable_>> obj.derivedVariable_;
    return in;

int main()

    unsigned int choice = 0;
    vector<unique_ptr<Base>>vec;
    while (true)
    
        cout << endl << "1. Add object of base class" << endl;
        cout << endl << "2. Add object of derived class" << endl;
        cout << endl << "3. Display all added objects to vector";
        cout << endl << "Choose option: ";
        cin >> choice;
        switch (choice)
        
        case 1:
        
            Base* ptr = new Base();
            cin >> *ptr;
            vec.push_back(unique_ptr<Base>(ptr));
            
            break;
        
        case 2:
        
            Derived* ptr = new Derived();
            cin >> *ptr;
            vec.push_back(unique_ptr<Base>(ptr));
            //delete ptr; <- it can't be here.
            break;
        
        case 3:
            cout << "Displaying...\n";
            for (size_t i = 0; i < vec.size(); i++)
            
                vec[i]->display();
            
            cout << "---------------------\n";
            break;

        
    

【问题讨论】:

Derived 对象将在 vec 销毁时被切片,因为 Base 析构函数不是 virtual 请阅读minimal reproducible example。您的代码缺少包含,更重要的是缺少示例输入、输出和预期输出。我冒着风险写了一个答案,但我无法确定它是否能解决你的问题,因为我无法找到有意义的输入,而且我不知道什么是错误/正确的输出 确实有帮助,谢谢。 【参考方案1】:

您的代码中没有切片。您忘记将Base::display 声明为虚拟,因此在Base* 上调用display 将调用Base::display

class Base

protected:
    string baseVariable_;
public:
    virtual void display() 
    // ^^----------------------------------------------- !!!
        cout << "BaseVar: " << baseVariable_ << endl;
    
    friend istream& operator>>(istream& in, Base& obj);
    virtual ~Base() 
;

对于多态类型,您还需要添加一个虚拟析构函数。

【讨论】:

你在这个特定的代码中是对的,添加 virtual 解决了这个问题。我的主程序中有虚拟显示方法,但它也不起作用。我通过重写矢量/对象创建来解决这个问题。谢谢! @RektLeft 查看我对您问题的评论。如果没有virtual,它就无法按您期望的方式工作。您的代码中可能有更多错误 我知道如果我想编辑派生类的方法,'virtual' 是必须的,但我忘了它。 @RektLeft 是的,没关系,但是当它不能解决问题时,你不应该接受这个答案。 “重写向量/对象创建”是什么意思? 但它确实修复了上面的代码,所以它必须是一个可接受的答案。我的意思是来自线程的代码。 What do you mean by "rewriting vector/object creation"? 从字面上看,只是删除了所有内容并从头开始。

以上是关于在基类类型的向量中保存的基对象和派生对象被切片的主要内容,如果未能解决你的问题,请参考以下文章

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

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

纯虚函数和抽象类

c++ 在基类类型的向量中调用子类方法

多态与重载

继承中的基类是不是复制到派生类?