【问题标题】:How to clone an object without copy constructor如何在没有复制构造函数的情况下克隆对象
【发布时间】:2018-04-05 17:40:28
【问题描述】:

根据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++: Deep copying a Base class pointer

【问题讨论】:

  • 而不是将base的虚拟clone函数声明为pure,也许实现它并且在派生类中覆盖它时,另外调用基本版本?
  • 移动构造函数还是方法?
  • @Charles 链接什么代码? OP链接指南并跳转到特定部分,其中不仅包含代码,还包含解释和信息。 OP 应该/可以复制和强调特定部分的事实可能值得商榷。不理解downvote,除非有重复
  • @Fureeish 哎呀。看到一个github链接。
  • 我编辑了我的问题。感谢您的关注。

标签: c++ c++14 deep-copy


【解决方案1】:

我认为最简单的方法是实际使特殊成员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));
    }
    // ...
};

【讨论】:

  • 出于好奇,是否有任何理由保留赋值运算符?如果您直接将这些类型的对象相互分配,您只需要这样做,如果通过指针处理对象,我无法想象这是类型安全的。
  • @templatetypedef 取决于我猜。分配D 可能是安全的,但可能不是。
  • clone() 必须是公开的,如果你想复制一个 D 但只有它的 A*
  • @MichaëlRoy 不明白。 clone()公开的吗?
  • A::clone() 必须是公开的而不是私有的。这就是使clone 虚拟化的想法。
【解决方案2】:

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

virtual unique_ptr<B> clone() override
{
    return make_unique<D>(*this);
}

这会调用对象自己的(受保护的)复制构造函数,而后者又会调用基的(受保护的)复制构造函数等。

请注意,这里不需要使用 CRTP。您只需要使用良好的老式复制构造函数即可。

【讨论】:

    猜你喜欢
    • 2012-02-14
    • 2011-11-03
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 2013-10-22
    相关资源
    最近更新 更多