如何在没有复制构造函数的情况下克隆对象

How to clone an object without copy constructor

本文关键字:情况下 对象 构造函数 复制      更新时间:2023-10-16

根据CppCoreGuideline,我应该禁用基类的复制构造函数并提出一个克隆方法:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-copy-virtual

例如:

class B {
   public:
     explicit B() = default;
     B(B&&) = default; // Move constructor
     B& operator=(B&&) = default; // Move assignment operator
     B(const B&) = delete; // Copy constructor
     B& operator=(const B&) = delete; // Copy assignment
     virtual ~B() = default;
     virtual unique_ptr<B> clone()
     {
        return unique_ptr<B>{new B{*this}}; // how do this without copy constructor ?
     }
    private:
     int c;
     int d;
};
class D : public B {
    public:
     explicit D() = default;
     D(D&&) = default; // Move constructor
     D& operator=(D&&) = default; // Move assignment operator
     D(const B&) = delete; // Copy constructor
     D& operator=(const D&) = delete; // Copy assignment
     virtual ~D() = default;
     virtual unique_ptr<B> clone() override
     {
          //  how can I copy all private data member of base class ???
     }
};

但是如何在克隆方法中复制所有私有数据成员?显然,我将使用 CRTP 模式:C++:深度复制基类指针

我认为

最简单的方法是实际使特殊成员protected而不是deleted。这仍然可以防止切片,但更容易实现clone()。请注意,复制成员和移动成员都需要以这种方式处理。

class B {
public:
    // if this is truly intended to be a polymorphic base class, it probably
    // doesn't make sense for the base to be able to clone itself.
    virtual unique_ptr<B> clone() = 0;
protected:
    B(B const& ) = default;
    B& operator=(B const& ) = default;
private:
    int c;
    int d;
};

这也允许派生类轻松执行此操作:

class D : public B {
public:
    D(D const& ) = default; // this is safe now
    D& operator=(D const& ) = default;
    unique_ptr<B> clone() override {
        return unique_ptr<D>(new D(*this));
    }
    // ...
};

与其禁用复制构造函数,不如考虑将其标记为受保护。这样,类的客户端就不会意外创建副本,但类的实例可以根据需要调用复制构造函数来实现clone函数。可以使用复制构造函数的默认版本,前提是您没有执行任何显式资源管理。然后,要实现clone,您可以执行以下操作:

virtual unique_ptr<B> clone() override
{
    return make_unique<D>(*this);
}
这将调用对象自己的(受保护的)复制构造函数

,而该构造函数又将调用基的(受保护的)复制构造函数等。

请注意,此处无需使用 CRTP。使用好的老式复制构造函数应该是你所需要的。

相关文章: