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

Почему мне приходится обновлять виртуальную функцию при переопределении [С++]

#include <iostream>
using namespace std;

class Duck {
public:
        virtual void quack() = 0;
};

class BigDuck : public Duck {
public:
  //  void quack();   (uncommenting will make it compile)

};

void BigDuck::quack(){ cout << "BigDuckDuck::Quack\n"; }

int main() {
        BigDuck b;
        Duck *d = &b;
        d->quack();

}

Приведенный выше код не компилируется. Однако, когда я объявляю виртуальную функцию в подклассе, тогда он компилируется отлично.

Если у компилятора уже есть подпись функции, которую подкласс будет переопределять, то почему требуется повторная декларация?

Любые идеи?

4b9b3361

Ответ 1

Требуется повторная декларация, потому что:

  • Стандарт так говорит.
  • Это облегчает работу компилятора, не поднимаясь вверх по иерархии, чтобы проверить, существует ли такая функция.
  • Возможно, вы захотите объявить его ниже в иерархии.
  • Чтобы создать экземпляр класса, компилятор должен знать, что этот объект конкретный.

Ответ 2

Если вы измените:

virtual void quack() = 0;

к

virtual void quack();

Он будет компилироваться без реализации quack() в HugeDuck.

the = 0; в конце объявления функции, по сути, говорит, что все BigDucks будут крякать, но что это должно быть реализовано каждой производной утиной. Удалив value = 0; кряк BigDuck будет вызван, если вы не примените шарлатан в HugeDuck.

РЕДАКТИРОВАТЬ: Прояснить value = 0; говорит, что производный класс будет иметь определение для функции. В вашем примере ожидается, что HugeDuck определит quack(), но, как вы его прокомментировали, это не так.

В качестве побочного примечания, поскольку все утки могут ошеломить, возможно, ваш оригинальный класс Duck, который мы не видим, должен реализовать quack() вместо?

Ответ 3

Поскольку С++ отделяет "объявление" от "полиморфизма": любая функция нуждается в объявлении для компилятора, независимо от того, является ли она виртуальной или нет.

Ваш пример не подходит достаточно далеко, у него есть проблема "абстрактного класса": BigDuck не может быть создан, потому что у него нет реализации шарлата в нем.

Обобщая проблему, мы можем объявить базовую функцию не чистой виртуальной:

class Duck { public: virtual void quack(){} };

class BigDuck : public Duck {}; 
void BigDuck::quack(){ cout << "QUACK!"; }//overrides, but doesn't declare

Здесь компилятор будет жаловаться, что он имеет символ BigDuck::quack, который не был объявлен. Это не имеет ничего общего с абстрактными классами или чем-то еще.

(Примечание: gcc говорит:   error: no 'void BigDuck::q()' member function declared in class 'BigDuck' )

Ответ 4

Определение Quack() в вашем базовом классе является "абстрактным" - оно не имеет реализации. Это сообщает компилятору, что ваш производный класс должен его реализовать. Несоблюдение этого является ошибкой компиляции.

Ответ 5

BigDuck может быть другим абстрактным классом, и вы можете не захотеть реализовать quack, пока не дойдете до базового класса ReallyBigDuck.

Ответ 6

Пока вы не предоставите реализацию, ll классы, которые наследуют класс, содержащий PVF, являются абстрактными - они не могут быть созданы. Чтобы обеспечить такую ​​реализацию, вы должны объявить функцию в классе.

Ответ 7

Объявление методов в каждом классе подскажет компилятору, что класс предоставляет различную реализацию метода.

Кроме того, если вы хотите создать объекты BigDuck в стеке, то как компилятор должен знать подпись quack().

BigDuck aDuck;
aDuck.quack();