c++ - 没看懂Stroustup先生建议删除抽象类Shape的copy default和move操作

标签 c++ c++11

我试图理解作者在他的新书(TCPL 第 4 版)中 3.3.4 Suppressing Operations 中的建议,但无济于事。

书摘

Using the default copy or move for a class in a hierarchy is typically a disaster: Given only a pointer to a base, we simply don’t know what members the derived class has (§3.3.3), so we can’t know how to copy them. So, the best thing to do is usually to delete the default copy and move operations; that is, to eliminate to default definitions of those two operations:

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();
};

Now an attempt to copy a Shape will be caught by the compiler. If you need to copy an object in a class hierarchy, write some kind of clone function (§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; 

}    

最佳答案

如果您只有一个指向 Shape 的指针,那么您不可能制作实际实现的拷贝 - 它(很可能)会更大,因此您的拷贝将被“切片” ”。在您的示例中,Circle 将有一个额外的 int a;这不是 Shape 类的一部分 - 如果您只是简单地复制一个 Shape 类对象而不知道它是一个 Circle (多态性的全部意义在于,在泛型函数中处理对象时,您不应该“知道”什么对象是什么类型)

为了避免因不小心使用类似的东西而引起的问题:

*q = *p; 

最好“删除”允许您这样做的运算符

但是,由于您描述的情况需要复制构造函数,因此一种解决方案是使其 protected - 防止派生类以外的其他东西使用它,并且可以正常工作。

感谢下面的 robson(还有一个晚上的 sleep ),解决方案显然是在 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;
};

它尝试使用 Shape 复制构造函数的原因是因为您自己的类中没有。你应该!

您也可以这样做(正如 Robson 解释的那样):

class Circle: public Shape
{
    public:
    Circle(int i) : a(i) {}
    Circle* clone() const { return new Circle(a); }
    int a;
};

而且根本不需要复制构造函数。这两种解决方案都解决了“您正在尝试使用已删除的 Shape(const Shape &) 构造函数。一旦您看到它,它真的很明显。

关于c++ - 没看懂Stroustup先生建议删除抽象类Shape的copy default和move操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17912889/

相关文章:

python - 如何在 python 中将十六进制转换为 ascii 十六进制字符串?

c++ - 我什么时候应该选择复制省略而不是通过 const 引用传递参数?

c++ - 是否可以从模板参数中提取数组大小?

c++ - 为什么 std::queue 使用 std::dequeue 作为底层默认容器?

c++ - static_assert signed shift right 具有二进制补码行为是否合法?

c++ - 使用 SFML 移动对象

c++ - 在 QGraphicsItem 中找到最大的 X pos 值

c++ - 数组分配

cuda 5.0支持的c++版本

C++ 为什么我可以在类定义中初始化静态 const char 但不能初始化静态 const double?