Почему мне приходится обновлять виртуальную функцию при переопределении [С++]
#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();
}
Приведенный выше код не компилируется. Однако, когда я объявляю виртуальную функцию
в подклассе, тогда он компилируется отлично.
Если у компилятора уже есть подпись функции, которую подкласс будет переопределять, то почему требуется повторная декларация?
Любые идеи?
Ответы
Ответ 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();