[英]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 )。
如果您确实想要复制分配,则可以使复制分配运算符为虚拟的,并通过以下方式小心地在派生类中实现正确的行为:
Base::operator=
来分配基类成员,并且 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.