Подтвердить что ты не робот

Почему виртуальная функция скрывается?

У меня есть следующие классы:

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, который показывает то же поведение.

4b9b3361

Ответ 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

Как он сказал:

"В С++ нет перегрузки по областям"

но если вы хотите

"Это легко сделать с использованием объявления-объявления"