Как наследовать некоторые кандидаты полиморфной функции?

#c #inheritance #polymorphism

#c #наследование #полиморфизм

Вопрос:

Я хочу определить функцию в базовом классе и функцию с тем же именем и другой сигнатурой в подклассе, подобном этому:

 class A {
public:
  void foo () {}
};

class B : public A {
public:
  void foo(int x) {}
};

int main() {
  B b;
  b.foo();
}
  

Но это вызывает ошибку компиляции: no matching function for call to ‘B::foo()’ .
Если я прокомментирую foo определение в классе B, оно скомпилируется.
Как решить проблему?

Чего я действительно хочу, так это определить полиморфный интерфейс в базовом классе и переопределить семантику в дочерних классах.

UPD: Спасибо, ответы сработали для этого примера. Но, похоже, это не работает с templates: sort.h

 ...
class Sort {
public:
  template <typename TArr>
  static TArramp; sort(TArramp; array) { return sort(array, array.size()); }
};

class BubbleSort : public Sort { // add inheritance
public:
  using Sort::sort;
  template <typename TArr>
  static TArramp; sort(TArramp; array, size_t len) {
     ...
  }
};
  

test.cpp

 ...
int main () {
  ...
  std::array<int, 5> test_array {3, 2, 5, 1, 4};
  BubbleSort::sort(test_array)
  ...
}
  

Когда я запускаю это, я получаю:

 sort.h: In instantiation of ‘static TArramp; Sort::sort(TArramp;) [with TArr = std::array<int, 5ul>]’:
test.cpp:9:30:   required from here
sort.h:17:47: error: no matching function for call to ‘Sort::sort(std::array<int, 5ul>amp;, std::array<int, 5ul>::size_type)’
   static TArramp; sort(TArramp; array) { return sort(array, array.size()); }
                                               ^
sort.h:17:16: note: candidate: template<class TArr> static TArramp; Sort::sort(TArramp;)
   static TArramp; sort(TArramp; array) { return sort(array, array.size()); }
                ^
sort.h:17:16: note:   template argument deduction/substitution failed:
sort.h:17:47: note:   candidate expects 1 argument, 2 provided
   static TArramp; sort(TArramp; array) { return sort(array, array.size()); }
  

Почему это происходит?

UPD: Понял это.

Ответ №1:

Без этого virtual A::foo() не определяется полиморфный интерфейс.

В любом случае, вы можете сделать A::foo() видимым через B с using объявлением:

 class B : public A {
public:
  using A::foo;
  void foo(int x) {}
};
  

Это обеспечивает полиморфизм в той степени, в какой вы принимаете перегрузку функции как полиморфизм — т.Е. A::foo() и B::foo() образуют набор перегрузки, и компилятор выбирает, какой вызывать, на основе переданных вами параметров (если таковые имеются), таким же образом, как если бы B содержал две перегруженные функции (с теми же сигнатурами, что и существующие A::foo и B::foo ).

Ответ №2:

Но это вызывает ошибку компиляции: no matching function for call to ‘B::foo()’

Попробуйте using-declaration :

 class A {
public:
    void foo() {}
};

class B : public A {
public:
    using A::foo;
    void foo(int x) {}
};
  

Чего я действительно хочу, так это определить полиморфный интерфейс в базовом классе и переопределить семантику в дочерних классах.

Ну, вы должны сделать так, чтобы функция базового класса virtual имела те же параметры при переопределении ее. В противном случае, как функция подкласса должна вызываться через ссылку / указатель на базовый класс?

Ответ №3:

Функция f из производного класса просто скрывает все функции с одинаковым именем из базового класса.

Для решения этой проблемы вы можете использовать using-declaration:

 class B : public A {
public:
  using A::foo;
  void foo(int x) {}
};
  

Комментарии:

1. Я не думаю, что это «проблема». Это во многом задумано.

2. @KerrekSB Определенно, «проблема» — не самое лучшее слово в таком контексте 🙂