Оператор присваивания недоступен в производном классе - PullRequest
0 голосов
/ 06 февраля 2019

Оператор присваивания в базовом классе, по-видимому, недоступен в производном классе.Учитывая этот код:

#include <iostream>

class A{
    int value;
public:
    A& operator=(int value){
        this->value = value;
        return *this;
    }
};

class B : public A{};

int main(){
    B b;
    b = 0; // Does not work
    return 0;
}

GCC 6.4 говорит:

ошибка: нет совпадения для 'operator =' (типы операндов 'B' и 'int')

Что происходит?

Ответы [ 4 ]

0 голосов
/ 06 февраля 2019

Каждый класс имеет по крайней мере один оператор присваивания, неявно определенный, когда мы сами его не предоставляем.

И когда функция-член в производном классе определяется с тем же именем, что и член в базовом классе, он скрывает все определения базового класса для этого имени.

Вы можете использовать объявление using, но имейте в виду, что оно вытянет всех членов с именем operator= и разрешит подобный код:

A a;
B b;
b = a;

Что немного сомнительно.

0 голосов
/ 06 февраля 2019

Проблема в том, что компилятор добавит оператор неявного присваивания для класса B, объявленного как

B& operator=(const B&);

. Этот оператор скрыт оператор из A, поэтому компилятор не будет знать об этом.

Решение состоит в том, чтобы сообщить компилятору также использовать оператор из A с ключевым словом using:

class B : public A
{
public:
    using A::operator=;
};
0 голосов
/ 06 февраля 2019

Как указывают другие существующие ответы, неявно сгенерированный оператор присваивания B скрывает оператор присваивания, определенный в A.Это верно для любой не виртуальной функции-члена в базовом классе, единственной особенностью здесь является автоматически сгенерированный оператор присваивания.

Но сначала попытайтесь выяснить, действительно ли вы хотите это сделать.Представьте, что в вашем классе B есть члены-данные, которые нужно каким-то образом инициализировать.Как использование назначения из A влияет на эти элементы данных?A ничего не знает о своих производных элементах данных класса, их бы не трогали.Посмотрите на следующий сценарий, в котором оператор присваивания был сделан доступным с помощью директивы using:

class B : public A {
   public:
      using A::operator=;

      int m = 0; // Default-initialize data member to zero
};

B b;
b.m = 42;
b = 0; // Doesn't touch B::m... intended? A bug? Definitely weird.

Так что да, это возможно, но подвержено ошибкам и опасно, особенно когда речь идет о будущих модификацияхподкласса.

0 голосов
/ 06 февраля 2019

Для того, чтобы это заработало, вам необходимо поместить operator= в область действия B:

class B : public A
{
public:
using A::operator=;
};

В соответствии со стандартом [class.copy.assign / 8]:

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

Таким образом, поскольку B::operator= был неявно объявлен, он скрыл A::operator=, что требует, чтобы вы перенесли его в область действия, если хотите его использовать.

Дальнейшая цитата из стандарта [over.ass / 1]

Оператор присваивания должен быть реализован нестатической функцией-членом с ровно одним параметром. Поскольку оператор оператора копирования = неявно объявляется для класса, если он не объявлен пользователем (15.8), оператор назначения базового класса всегда скрыт оператором копирования копии производного класса.

Акцент мой.

...