Наследование родительского оператора присваивания, когда дочерний оператор неявно удаляется

В GCC 4.6 возможно наследовать операторы присваивания родителя, даже если дочерние операторы присваивания неявно удалены из-за конструктора перемещения. В более поздних версиях GCC (а также Clang) это больше невозможно. Как правильно, чтобы дочерний класс использовал операторы присваивания родителя?

struct A
{
A & operator=(A const & other) = default;
};

struct B : public A
{
B() {}
B(B && other) {}

using A::operator=;
};

int main()
{
B b1, b2;
b1 = b2; // error: use of deleted function because B's operator= is implicitly deleted due to move constructor
return 0;
}

3

Решение

Удаленная функция все еще объявленный, только определение удален Расширяя это в вашем определении класса:

struct B : A {
using A::operator=;               // A& operator=(const A&)
B& operator=(const B&) = delete;
};

На данный момент, вы можете заметить, что есть две декларации для operator= в производном типе первый (введенный в область видимости посредством используя декларирование) занимает const A& аргумент, в то время как второй принимает const B& и является удаленный.

Когда вы позже попробуйте назначение:

B b1, b2;
b1 = b2;

Оба объявления видятся компилятором, а второе лучше подходит. Потому что это помечено как удаленный Вы получаете ошибку. Если у вас есть, с другой стороны, назначен A Объект, который бы работал, как ожидалось:

B b1, b2;
b1 = static_cast<A&>(b2); // works, BUT...

Проблема этого подхода заключается в том, что он копирует только базовые подобъекты, что, вероятно, не то, что вам нужно. Если вы просто хотите получить такое же поведение, как если бы присваивание было сгенерировано компилятором, вам нужно запросить его:

struct B : A {
// ...
B& operator=(const B&) = default;
};
6

Другие решения

Это будет зависеть от того, что вы хотите, чтобы произошло, когда вы назначаете производный тип для себя. Если вы хотите, чтобы дочерний оператор присваивания работал как «обычный», несмотря на то, что оператор перемещения подавляет неявное генерирование, вы можете просто вернуть дочернее присваивание обратно в класс, используя это:

    B &operator=( B const & ) = default;

Это, вероятно, будет эквивалентно тому, что сделал GCC 4.6. Я считаю, что GCC 4.6 должным образом не подавляет сгенерированные операторы, как того требует стандарт, поэтому вы, вероятно, просто получали обычное поведение оператора присваивания вместе с любыми перегрузками из базового класса, которые использовались в объявлении using.

Если вы на самом деле хотите назначить только базовую часть класса, вам нужно реализовать свой собственный оператор присваивания:

B &operator=( B const &that ) {
static_cast<A&>(*this) = that;
return *this;
}

К сожалению, у меня нет GCC 4.7, чтобы попробовать его прямо сейчас, но я не удивлюсь, если вы действительно получаете оператор присваивания базового класса в своем производном классе, но оператор удаленного присваивания производного класса лучше подходит для вашего примера , Вы можете проверить это, попробовав эту строку в вашем main ():

    b1 = static_cast<A const&>(b2);

2

По вопросам рекламы [email protected]