如果有成员,基 class 中的默认析构函数禁用子 class 中的移动构造函数

Defaulted destructor in base class disable move constructor in child class if there is a member

为什么 Base1 中的默认( 用户声明)析构函数阻止在 Child1 class 中生成移动 constructor/operator,但是当我将成员 data 从 Base (Base2) 移动到 Child (Child2) class?

时一切正常
struct Data {
    Data() {}
    Data(Data&&) noexcept { cout << "Move constructor" << endl; }
    Data& operator=(Data&&) noexcept {
        cout << "Move assign" << endl;
        return *this;
    }
    vector<int> vec;
};

struct Base1 {
    virtual void fun() { cout << "Base1::fun" << endl; }
    virtual ~Base1() = default;
    Data data;
};

struct Child1 : public Base1 {
    void fun() override { cout << "Child1::fun" << endl; }
};

struct Base2 {
    virtual void fun() { cout << "Base2::fun" << endl; }
    virtual ~Base2() = default;
};

struct Child2 : public Base2 {
    void fun() override { cout << "Child2::fun" << endl; }
    Data data;
};

int main() {
    Child1 c1;
    auto obj1 = std::move(c1);  // error

    Child2 c2;
    auto obj2 = std::move(c2);
}

我目前的理解是,当我在Base(BaseDel)中声明析构函数为“default”时,那么move构造函数在Base(BaseDel中应该是“deleted” =]) 和儿童 (ChildDel) class。这个对吗?我认为,成员位置无关紧要。如果我明确地这样做,我会得到预期的错误:

struct BaseDel {
    BaseDel() {}
    virtual void fun() { cout << "BaseDel::fun" << endl; }
    BaseDel(BaseDel&& st) = delete;
    virtual ~BaseDel() = default;
};

struct ChildDel : public BaseDel {
    ChildDel() {}
    void fun() override { cout << "ChildDel::fun" << endl; }
    Data data;
};

int main() {
    ChildDel cd;
    auto objd = std::move(cd);  // OK, expected error
}

隐式移动构造函数不是(仅)删除,当您有一个用户-声明的析构函数,如 Base1Base2.

因此在重载决议中永远不会考虑移动构造函数,因此 auto obj1 = std::move(c1);,虽然它可以调用 Child1 的移动构造函数,但需要回退到 [=10 的复制构造=] 子对象。

Base1Child1的隐式声明的复制构造函数都被定义为已删除,因为Data的隐式声明的复制构造函数被定义为已删除,因为Data 有一个用户定义的移动构造函数。因此 auto obj1 = std::move(c1); 将失败并显示隐式声明的复制构造函数被删除的错误。

对于Base2,复制构造函数未定义为已删除,因为它没有Data成员,因此auto obj2 = std::move(c2);将调用Child2的移动构造函数(也使用 Data 的移动构造函数),但对 Base2 子对象使用 复制构造函数