繁体   English   中英

可克隆层次结构中的C ++复制构造函数和赋值

[英]C++ copy constructors and assignments in cloneable hierarchy

有一个众所周知的clone惯用法,可通过指向Base类的指针复制Derived对象。

class Base{
  int b;
public: 
  virtual unique_ptr<Base> clone() const = 0;
  virtual ~Base() = default;
};

class Derived : public Base {
  int d;
public:
  virtual unique_ptr<Base> clone() const override {
    return std::make_unique<Derived>(*this);
  }
}

但是,在这种情况下,我找不到明确的说明如何定义副本构造函数和赋值。 这就是我想应该在Base类中完成的方式:

class Base {
protected:
  Base(const Base&) = default;
private:
  Base& operator=(const Base&) = delete;
}

是否有必要(为了避免潜在的碎片)? 这是正确的方法吗? 是否足够,还是应该在Derived类中添加此类声明?

由于派生类使用复制构造函数创建克隆,因此您可能希望使复制构造函数不公开,以避免意外切片,但派生类可以访问它。

protected满足此要求。 由于编译器生成的副本构造函数是public因此需要将其应用于每个类的副本构造函数。 将相同的处理应用于赋值运算符也很有意义。

这样也可以防止std::make_unique访问副本构造函数:

class A
{
protected:
    A(A const&) = default;
    A& operator=(A const&) = default;
public:
    A();
    virtual std::unique_ptr<A> clone() const = 0;
};

class B : public A
{
protected:
    B(B const&) = default;
    B& operator=(B const&) = default;
public:
    B();

    std::unique_ptr<A> clone() const override { 
        return std::unique_ptr<A>(new B(*this)); 
    }
};

除非需要,否则删除副本分配运算符可能是一个好主意。

Base删除operator=(const Base&)就足够了,因为如果基类没有副本赋值运算符,则隐式声明的副本赋值运算符被定义为对于派生类已删除(请参见cppreference.com )。

如果您确实想要复制分配,则可以使复制分配运算符为虚拟的,并通过以下方式小心地在派生类中实现正确的行为:

  1. 调用Base::operator=来分配基类成员,并且
  2. 使用dynamic_cast来确保派生类的成员具有正确的类型,以分配派生类的成员。

如果正确完成,这将避免对象切片,并保留正确的类型。

一个示例(省略了复制构造函数的详细信息):

  struct Point {
    virtual Point& operator=(const Point& p) =default;
    int x;
    int y;
  };  

  struct Point3d :public Point{
    virtual Point3d& operator=(const Point& p);
    int z;
  };

  Point3d& Point3d::operator=(const Point& p)
  {
    Point::operator=(p);
    auto p3d = dynamic_cast<const Point3d*>(&p);
    if(p3d){
      z = p3d->z; 
    } else {
      z = 0;
    }
    return *this;
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM