Деструктор по умолчанию в базовом классе отключить конструктор перемещения в дочернем классе, если есть член - PullRequest
2 голосов
/ 08 февраля 2020

Почему деструктор по умолчанию (, объявленный пользователем ) в Base1 предотвращает создание конструктора / оператора перемещения в классе Child1, но все работает нормально, когда я перемещаю элемент data из Base (* 1006) *) к классу Child (Child2)?

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

В настоящее время я понимаю, что когда я объявляю деструктор как «default» в Base (BaseDel), тогда конструктор перемещения должен быть «deleted ”в базовом (BaseDel) и в детском (ChildDel) классе. Это правильно? Я думаю, местоположение члена не должно иметь значения. Если я сделаю это явно, я получу ожидаемую ошибку:

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
}

1 Ответ

3 голосов
/ 08 февраля 2020

Неявный конструктор перемещения не (только) удален , он не объявлен в первую очередь, когда у вас есть объявленный пользователем деструктор, как в случае с Base1 и Base2.

Поэтому конструктор перемещения никогда не может рассматриваться в разрешении перегрузки, поэтому auto obj1 = std::move(c1);, в то время как он может вызывать конструктор перемещения Child1, должен вернуться к копированию конструкции для Base1 подобъект.

Неявно объявленные конструкторы копирования как Base1, так и Child1 определены как удаленные, поскольку неявно объявленный конструктор копирования Data определен как удаленный, поскольку Data имеет пользовательский конструктор перемещения. Поэтому auto obj1 = std::move(c1); завершится с ошибкой, что неявно объявленный конструктор копирования будет удален.

Для Base2 конструктор копирования не определен как удаленный, поскольку он не имеет члена Data и поэтому auto obj2 = std::move(c2); вызовет конструктор перемещения Child2 (который также использует конструктор перемещения Data), но использует конструктор копирования для подобъекта Base2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...