Вот что я понял за последние два месяца, изучая семантику Move:
- Конструктор перемещения неявно вставляет SomeClass::operator=(const SomeClass&) = delete в конце определения класса, отключая оператор присваивания копирования
- Такое поведение обеспечивает соблюдение Правила 5, в котором используется либо Конструктор перемещения, либо оператор Перемещение назначения - все следующие 5 должны (или в некоторых случаях их части) быть реализовано:
Конструктор перемещения - Конструктор копирования
- Оператор перемещения=
- Оператор копирования=
- Деструктор
Однако, если я хочу повторно использовать операторы присваивания из базового (или родительского/супер) класса - проще говоря,
Код: Выделить всё
using SomeBaseClass::operator=;
Код: Выделить всё
class SomeClass: public SomeBaseClass {
public:
SomeClass(SomeClass&& other);
using SomeBaseClass::operator=;
...
// Compiler: let me help you!
SomeClass& SomeClass::operator=(const SomeClass&) = delete;
}
< pre class="lang-cpp Prettyprint-override">
Код: Выделить всё
class SomeClass a, b;
a = b; // Use of deleted func!
Вопрос
Очевидно, снова писать операторы для подклассов, которые внутри просто оборачивают базу операторы класса должны работать и работают. Еще всего 3 строки для каждого подкласса:
Код: Выделить всё
// using void to give up ability to chain like a = b = c
void SomeSubclass::operator=(const SomeSubclass& other) {
SomeBaseClass::operator=(other);
}
Вот MRE, представляющий это поведение (Compiler Explorer Live):
Код: Выделить всё
#include
class Derived;
// Interface class to reuse & enforce specific set of operations
// over multiple sibling subclasses
class SomeInterface {
protected:
// Function to allow subclass usage inside predefined operations
virtual Derived& get_derived() = 0;
public:
// destructor / move / copy assignment defined to satisfy Rule of 5 in subclasses
virtual ~SomeInterface() = default;
// Giving up ability to do a = b = c
void operator=(const Derived& other);
void operator=(Derived&& other);
};
// ...Now I'm not sure if this count as interface class, still doesn't have member data tho!
// Subclass implementing Interface
class Derived : public SomeInterface {
protected:
int some_data;
Derived& get_derived() override;
public:
Derived(int data) : some_data(data) {}
Derived(Derived&& other) noexcept;
Derived(const Derived& other);
// Some data accessors
int& get_data() { return some_data; }
const int& get_data() const { return some_data; }
// Using predefined operators provided by interface
using SomeInterface::operator=;
// No errors if we define wrapper
//void operator=(const Derived& other) {
// SomeInterface::operator=(other);
//}
};
// --- Implementations ---
Derived& Derived::get_derived() {
return *this;
}
Derived::Derived(Derived&& other) noexcept {
std::swap(some_data, other.get_data());
}
Derived::Derived(const Derived& other) {
some_data = other.get_data();
}
void SomeInterface::operator=(const Derived& other) {
get_derived().get_data() = other.get_data();
}
int main() {
Derived a(2);
Derived b(19);
a = b; //
Подробнее здесь: [url]https://stackoverflow.com/questions/78369718/elegant-way-to-mix-move-constructor-with-base-classs-copy-assignment-operator[/url]