Почему виртуальная функция скрывается?
У меня есть следующие классы:
class A {
public:
virtual void f() {}
};
class B : public A{
public:
void f(int x) {}
};
Если я скажу
B *b = new B();
b->f();
компилятор говорит об ошибке C2660: 'B:: f': функция не принимает 0 аргументов.
Разве функция B не перегружает ее, так как это виртуальная функция? Виртуальные функции скрываются так?
EDIT: я действительно хотел унаследовать B от A, который показывает то же поведение.
Ответы
Ответ 1
Предполагая, что вы выбрали B
для вывода из A
:
f(int)
и f()
- разные сигнатуры, поэтому разные функции.
Вы можете переопределить виртуальную функцию с помощью функции, которая имеет совместимую подпись, что означает либо идентичную подпись, либо та, в которой тип возврата является "более конкретным" (это ковариация).
В противном случае функция производного класса скрывает виртуальную функцию, как и любой другой случай, когда производный класс объявляет функции с тем же именем, что и функции базового класса. Вы можете поместить using A::f;
в класс B, чтобы отобразить имя
В качестве альтернативы вы можете назвать его как (static_cast<A*>(b))->f();
или как b->A::f();
. Разница в том, что если B
действительно переопределяет f()
, то первое вызывает переопределение, тогда как последнее вызывает функцию в A
независимо.
Ответ 2
Класс B не получается из A, поэтому функция F() не существует. Вы, вероятно, имели в виду:
class A {
public:
virtual void f() {}
};
class B : public A {
public:
void f(int x) {}
};
Изменить: Я пропустил скрытую функцию. См. Ответ Стива Джессопа для более подробного объяснения.
Ответ 3
Нет, и да, соответственно. Если вы хотите перегружать поведение, вам нужно сказать
using A::f;
в B.
Ответ 4
B не получается из A, правильное объявление:
class B : public A
Ответ 5
Когда у компилятора есть несколько способов разрешения символа, он должен выбрать, какой из них имеет приоритет, если код не говорит об этом иначе. То, что вы ожидаете, - это перегрузка, чтобы иметь приоритет над переопределением. (более, более, более, aaaaack! Извините, получил "over'whelmed" ).
В этом примере B наследует виртуальный метод, в котором подкласс предоставляет перегруженную версию. Перегрузки относятся к методам того же класса, используя одно и то же имя метода, но разные подписи. Поскольку B является подклассом A, он переопределяет f(), что означает, что он также не может быть перегрузкой в одно и то же время. Вот почему он скрыт.
Для класса A, объявляющий метод
virtual void f() {}
как виртуальный означает, что метод будет разрешен с использованием определенного набора правил, которые не согласуются с вашим объявлением b.
B *b = new B();
Создав "b" в качестве экземпляра "B", компилятору не нужно использовать виртуальную природу метода с тем же именем в "A".
Если вы заявили 'b', как этот
B *b = new A();
то вызов b- > f(); действительно будет ссылаться на метод в A, используя виртуальное разрешение.
Ответ 6
Кажется, что существует довольно похожий вопрос с ответом в Biern Stroustrup FAQ: http://www.stroustrup.com/bs_faq2.html#overloadderived
Как он сказал:
"В С++ нет перегрузки по областям"
но если вы хотите
"Это легко сделать с использованием объявления-объявления"