#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 Определенно, «проблема» — не самое лучшее слово в таком контексте 🙂