指定对不可复制的派生对象进行混叠的基础引用

Assignment of base references aliasing non copyable derived objects

本文关键字:引用 对象 可复制 派生      更新时间:2023-10-16

我与一位同事讨论了将抽象基类标记为不可复制的必要性。我认为没有必要这样做,因为基类是抽象的,因此我们不能有基类的实例,所以通过基类引用进行复制不是问题。派生类可以自己决定是否允许复制。然而,我的同事给我看了一个基本参考文献的分配案例,这让我有点惊讶。

#include <stdio.h>
struct B
{
    virtual void foo() = 0;
    virtual ~B(){}
};
struct D : public B
{
    D(int i): data(i){}
    void foo() override {printf("%d", data);}
    int data;
    D& operator=(D) = delete;
    D(const D&) = delete;
};
int main()
{
    D d(1);
    D d2(2);
    d.foo();
    d2.foo();
    B& b = d;
    B& b2 = d2;
    b.foo();
    b2.foo();
    b = b2; // what is this doing?
    b.foo();
    b2.foo();
    d.foo();
    d2.foo();
}

上面的代码输出:12121212。我真的不明白这里发生了什么。b = b2;做什么?我预料到这里会出现编译错误。

您没有定义复制赋值运算符,因此会默认使用一个。

默认的不是virtual,所以它会将d2B子对象的任何成员变量复制到dB子对象。(B::operator=D::operator=一无所知)。

像这样使用基类operator=在一般情况下确实会破坏封装;尽管在这种情况下,由于B没有成员变量,也没有基类,所以这一行实际上没有任何作用。

因此,在这里将B标记为不可编辑可能过于防御性;因为这将强制所做想要可复制的任何子类跳过重重关卡以重新启用复制。