我试图理解作者3.3.4 Suppressing Operations在他的新书(TCPL第4版)中的建议,但无济于事.
从书中摘录
对层次结构中的类使用默认副本或移动通常是一个灾难:只给出指向基类的指针,我们根本不知道派生类有哪些成员(§3.3.3),所以我们无法知道如何复制它们.所以,最好的办法是删除默认副本和移动操作; 也就是说,要消除这两个操作的默认定义:
class Shape {
public:
Shape(const Shape&) =delete; // no copy operations
Shape& operator=(const Shape&) =delete;
Shape(Shape&&) =delete; //no move operations
Shape& operator=(Shape&&) =delete;
~Shape();
};
Run Code Online (Sandbox Code Playgroud)
现在,编译器将捕获复制Shape的尝试.如果需要复制类层次结构中的对象,请编写某种克隆函数(第22.2.4节).
例如,下面的代码不能编译Shape(const Shape&) = delete;,因为clone()函数调用了Shape复制构造函数.
#include <iostream>
class Shape
{
public:
virtual ~Shape() {}
Shape() {}
Shape(const Shape&) {};
virtual Shape* clone() const = 0;
};
class Circle: public Shape
{
public:
Circle(int i) : a(i) {}
Circle* clone() const { return new Circle(*this); }
int a;
};
int main()
{
Shape* p = new Circle(1);
Shape* q = p->clone();
std::cout << dynamic_cast<Circle*>(p)->a << std::endl;
std::cout << dynamic_cast<Circle*>(q)->a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果你只有一个指向a的指针Shape,那么你就不可能复制实际的实现 - 它(很可能)会更大,所以你的副本将被"切片".在你的例子中,Circle将有一个额外的int a; 这不是Shape类的一部分- 如果你只是简单地复制一个Shape类对象而不知道它是一个会丢失Circle(而且多态性的全部意义在于你不应该"知道"什么对象在处理时是什么类型它在通用函数中)
为避免因意外使用以下内容而导致的问题:
*q = *p;
Run Code Online (Sandbox Code Playgroud)
最好"删除"允许你这样做的运算符
但是,由于您描述的情况需要复制构造函数,因此一种解决方案是使用它protected- 除了使用它的派生类之外的其他东西,并且正常工作.
感谢下面的robson(以及夜晚的睡眠),解决方案显然是制作复制构造函数Circle.仅仅因为你没有一个Shape并不意味着你不能在派生类中拥有一个:
class Circle: public Shape
{
public:
Circle(int i) : a(i) {}
Circle(const Circle& other) { a = other.a; } // Note this line!
Circle* clone() const { return new Circle(*this); }
int a;
};
Run Code Online (Sandbox Code Playgroud)
它试图使用Shape复制构造函数的原因是因为你自己的类中没有.你应该!
你也可以这样做(正如罗布森解释的那样):
class Circle: public Shape
{
public:
Circle(int i) : a(i) {}
Circle* clone() const { return new Circle(a); }
int a;
};
Run Code Online (Sandbox Code Playgroud)
根本不需要复制构造函数.这两种解决方案都解决了"你试图使用已删除的内容Shape(const Shape &) constructor.一旦你看到它就会很明显.
他的意思是,由于潜在的对象切片问题,让它们可以从外部访问是不好的。如果您不需要使类可克隆,那么删除就足够了,否则您可以将其设置为受保护,使其只能在其内部clone()和后继者中访问。