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(。
你可以使复制赋值运算符成为虚拟的,并仔细地在派生类中实现正确的行为
- 调用
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;
}
相关文章:
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 为用户定义的类正确调用复制构造函数/赋值运算符
- C++:关于使用 Stroustrup 示例移动构造函数/赋值的问题
- 初始值设定项列表与构造函数赋值与变量定义
- std::vector::emplace() 真的在面对抛出移动构造函数/赋值运算符时提供了强大的异常保证吗?
- 创建一个类并在C++中使用构造函数(赋值)
- 如何为具有自引用指针的类实现复制构造函数/赋值运算符
- 使typedef的构造函数/赋值运算符成为友元函数
- 复制构造函数+赋值运算符
- C++ 矢量从构造函数赋值对象,无需临时
- 具有std::原子成员变量的类的复制构造函数/赋值运算符出错
- 初始化对象时复制构造函数/赋值运算符混淆
- 默认情况下是默认的构造函数/赋值noexcept/constexpr
- 模板是否应该为不同类型的参数制作非 Rvalue 引用构造函数/赋值
- 为什么 std 类型不提供来自分配器不同源的转换构造函数/赋值
- 是否为派生类生成的移动构造函数/赋值运算符
- 复制构造函数/赋值运算符
- C++复制构造函数/赋值运算符错误
- 正在获取要使用的移动构造函数/赋值运算符
- 影响正确性的move构造函数/赋值操作符示例