Элегантный способ совместить конструктор Move с оператором присваивания Copy базового класса.C++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Элегантный способ совместить конструктор Move с оператором присваивания Copy базового класса.

Сообщение Anonymous »

Объяснение проблемы
Вот что я понял за последние два месяца, изучая семантику Move:
  • Конструктор перемещения неявно вставляет SomeClass::operator=(const SomeClass&) = delete в конце определения класса, отключая оператор присваивания копирования
  • Такое поведение обеспечивает соблюдение Правила 5, в котором используется либо Конструктор перемещения, либо оператор Перемещение назначения - все следующие 5 должны (или в некоторых случаях их части) быть реализовано:

    Конструктор перемещения
  • Конструктор копирования
  • Оператор перемещения=
  • Оператор копирования=
  • Деструктор


Однако, если я хочу повторно использовать операторы присваивания из базового (или родительского/супер) класса - проще говоря,

Код: Выделить всё

using SomeBaseClass::operator=;
в дочернем классе, который реализует Move Constructor, кажется недостаточным, как мы установили ранее - компилятор неявно вставляет это в конец определения дочернего класса, когда Move Конструктор определен.

Код: Выделить всё

class SomeClass: public SomeBaseClass {
public:
SomeClass(SomeClass&& other);
using SomeBaseClass::operator=;
...

// Compiler: let me help you!
SomeClass& SomeClass::operator=(const SomeClass&) = delete;
}
... Который, кажется, имеет гораздо более высокий приоритет при сопоставлении, затенение с использованием ~~:operator=, что приводит к следующей ошибке:
< 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]
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»