Оператор присваивания перегрузки в базовом классе - PullRequest
2 голосов
/ 24 июня 2019

У меня есть шаблонный класс с именем BaseSignal,

  template <class T>
  class BaseSignal
  {
    public:
    // Constructor
    BaseSignal(long buf_size, bool is_async, SimData *sim)
    ....

Из этого класса получены два других шаблонных класса, Net и Reg. (Для тех, кто заинтересован, я моделирую поведение параллельных и последовательных заданий в Verilog). Они определены как

  template <class T>
  class Net : public BaseSignal<T>
  {
    public:
    Net(long buf_size, bool is_async, SimData* sim)
      : BaseSignal<T>(buf_size, is_async, sim) {};
      ....

и аналогично для Reg.

В базовом классе я определил методы Set и Get как виртуальные,

    // Virtual settors
    virtual void Set(long val) {};
    virtual void Set(double val) {};

    // Virtual gettors
    virtual void Get(long* val) const {};
    virtual void Get(double* val) const {};

Поскольку Net и Reg имеют различное поведение для них. Итак, вот интересная часть.

+ = Перегрузочные работы в базовом классе

В базовом классе я определяю этот оператор для вызова виртуальных операций Set и Get, которые работают как положено.

В BaseSignal:

    BaseSignal<T>& operator+=(const double& rhs)
    {
      T rval;
      this->Get(&rval);
      this->Set(rval + static_cast<T>(rhs));
      return *this;
    }
    BaseSignal<T>& operator+=(const long& rhs)
    {
      T rval;
      this->Get(&rval);
      this->Set(rval + static_cast<T>(rhs));
      return *this;
    }

В моем коде у меня есть указатели net_real и net_int, а когда я делаю

  *net_real += 1.1;
  *net_int += 1l;

Чистые значения увеличиваются правильно. Вот странная часть

= Перегрузка не работает в базовом классе

Перегрузка = в классе Net работает нормально, как и ожидалось:

    Net<T>& operator=(const double& rhs)
    {
      this->Set(static_cast<T>(rhs));
      return *this;
    }
    Net<T>& operator=(const long& rhs)
    {
      this->Set(static_cast<T>(rhs));
      return *this;
    }

Но если я введу это в BaseSignal,

    BaseSignal<T>& operator=(const double& rhs)
    {
      this->Set(static_cast<T>(rhs));
      return *this;
    }
    BaseSignal<T>& operator=(const long& rhs)
    {
      this->Set(static_cast<T>(rhs));
      return *this;
    }

Я могу скомпилировать файл класса нормально, но когда я компилирую main.cpp, я получаю это:

ctests/main.cpp: In function 'int main()':
ctests/main.cpp:28:15: error: no match for 'operator=' (operand types are 'cpysim::Net<double>' and 'double')
   28 |   *net_real = 1.0;
      |               ^~~
In file included from ctests/main.cpp:9:
csrc/signals_nets.hpp:456:9: note: candidate: 'constexpr cpysim::Net<double>& cpysim::Net<double>::operator=(const cpysim::Net<double>&)'
  456 |   class Net : public BaseSignal<T>
      |         ^~~
csrc/signals_nets.hpp:456:9: note:   no known conversion for argument 1 from 'double' to 'const cpysim::Net<double>&'
csrc/signals_nets.hpp:456:9: note: candidate: 'constexpr cpysim::Net<double>& cpysim::Net<double>::operator=(cpysim::Net<double>&&)'
csrc/signals_nets.hpp:456:9: note:   no known conversion for argument 1 from 'double' to 'cpysim::Net<double>&&'

Я не уверен на 100%, что понимаю часть «кандидата». Он пытается вызвать конструктор копирования? И я также не понимаю, почему нет совпадения с операндами (operand types are 'cpysim::Net<double>' and 'double'), поскольку Net является производным от BaseSignal, и я определил оператор для этих операндов. Еще более загадочно, почему он работает для +=, а не =.

1 Ответ

4 голосов
/ 24 июня 2019

Это скрывающая имя проблема;производный класс имеет неявно сгенерированные operator= s, включая оператор назначения копирования и оператор назначения перемещения , которые hide operator= s базыкласс.

Так работает поиск имени .Когда имя operator= найдено в области производного класса, дальнейшая область, включая область базового класса, не будет исследована, поиск имени останавливается.После этого выполняется разрешение перегрузки на основе найденного имени и, наконец, ошибка компиляции.

operator+= такой проблемы нет;в производном классе нет (явно или неявно) объявленного operator+=.

Вы можете использовать using, чтобы ввести operator= базового класса в область действия производного класса.например,

template <class T>
class Net : public BaseSignal<T>
{
  public:
    using BaseSignal<T>::operator=;
  ...
};
...