避免在方法调用中进行对象切片

Avoiding object slicing in a method call

本文关键字:对象 切片 调用 方法      更新时间:2023-10-16

我一直在尝试重写我的程序,以允许继承类。我遇到了切片的问题。我最初在Test类中有Parent m_parent(因此在Test中没有动态分配),但我认为它可以解决我的问题,但它没有。我不知道我是在让我的问题变得更糟,还是像写一个复制构造函数(或其他简单的修复程序)一样简单。

class Parent
{
    public:
        Parent();
    private:
        string a;
};
class Child : public Parent
{
     private:
        string b;
};
class Test
{
     public:
        Test()
        {
            m_parent = new Parent;
        }
        void testFunction(Parent &parent)
        {
            *m_parent = parent;
        }
        ~Test()
        {
             delete m_parent;
        }
     private:
        Parent * m_parent;
};

这样做仍然会导致切片。。。

Child c("foo", "bar");
Parent * p = &c;
Test.testFunction(*p);

没有对象切片,但m_parent不会变成Child,只复制string a

如果你想在Test中保存一份,我建议使用Clone:

class Parent
{
public:
    virtual ~Parent() = default;
    virtual Parent* Clone() const { return new Parent(*this); }
private:
    string a;
};
class Child : public Parent
{
public:
    Child* Clone() const override { return new Child(*this); }
private:
    string b;
};
class Test
{
public:
    void testFunction(const Parent &parent)
    {
        m_parent.reset(parent.Clone());
    }
private:
    std::unique_ptr<Parent> m_parent;
};

是。此行:

*m_parent = parent;

导致对象被分割成Parent对象,而不管它到底是什么。

除此之外,在您的示例中还有许多错误代码行,但我想这只是因为这是一个非常具体的问题。

编辑:如何避免切片的建议:

template <class T>
void testFunction(T& t){
    static_assert(std::is_base_of<Parent,T>::value,"only subclasses of Parent may be passed to testFunction");
     delete m_parent;
     m_parent = new T(t); //or: new T(std::move(t));
}

第2版:如果您将子对象作为真实对象而不是父指针传递,也就是testFunction(myChild) ,那么这将起作用

EDIT3:@Jarod42对clone方法有很好的看法。这两种解决方案可以一起使用