Почему мне нужно повторно объявить переопределенные функции в производных классах в С++?
Предположим, что у меня есть следующий код:
class Iinterface
{
virtual void abstractFunction()=0;
};
class Derived : public Iinterface
{
void abstractFunction(); // Do I need this line?
};
Derived::abstractFunction()
{
// implementation here
}
Если я не добавляю эту строку, я получаю ошибку компиляции, в которой abstractFunction
не объявляется в Derived
. Я использую VS 2008.
Я не уверен, почему мне нужна эта конкретная строка (не путайте это с определением функции, которое предоставляется вне объявления класса), если я наследую от Iinterface
, должно быть очевидно, что я объявлен abstractFunction
. Это проблема с визуальной студией или она соблюдается стандартами С++?
Ответы
Ответ 1
Если объявление чистых виртуальных базовых функций подразумевалось во всех производных классах, то у вас никогда не было бы производного класса, который остается абстрактным по отношению к чисто виртуальной базовой функции. Вместо этого все производные классы создавали бы ошибки компоновщика. Это было бы чрезвычайно противоречивым и запутанным, и это сделало бы язык менее выразительным.
Более того, это даже не имеет смысла: вопрос о том, является ли производный класс абстрактным или нет, должен быть известен везде во время компиляции. Реализация переделки обычно предоставляется только в одной единице перевода, поэтому было бы невозможно сообщить о том, что вы на самом деле означаете, что функция будет переопределена для остальной части программы.
Ответ 2
- Да. Если вы хотите создать объект
class Derived
- Нет. Если вы хотите сохранить
class Derived
также абстрактно
- Нет. Если существует промежуточный класс, который уже переопределил функцию
например между
Iinterface
и Derived
существует class Intermediate
, который переопределил abstractFunction()
; поэтому теперь для class Derived
необязательно переопределять те же
Изменить. С измененным заголовком вопроса
Почему мне нужно повторно объявлять переопределенные функции в производных классах в c++?
Это потому, что грамматика компилятора С++ требует, чтобы каждая функция-член class
(или namespace
или файл) была объявлена внутри тела class
(или namespace
или файла). Будь это virtual
или нормальная функция.
Существует нет хорошая причина для нарушения этой согласованности только для функций virtual
.
Ответ 3
Функция, которая заканчивается на =0
, называется deleted function
, это полезно, когда вам не нужны объекты, которые используют определенные конструкторы (например, unique_ptr
, у которого есть удаленная копия ctor).
Если функция virtual
удаляется, то по стандарту класс становится абстрактным. Поскольку в большинстве случаев прототип класса и тела функции класса находится в отдельных файлах, это означает, что, если вы явно не укажете в прототипе, что вы переопределяете удаляемую виртуальную функцию, вы НЕ ПЕРЕДАВАЕТ удаляемую виртуальную функцию. Компилятор не должен просто указывать, что вы хотели бы включить функцию там, как только она увидит реализацию в совершенно другом файле.
Помните, что идея прототипа/реализации не является единственным способом написания кода, вы также можете поместить реализацию в класс (это можно сделать, если код достаточно мал, и вы хотите встроить эту функцию). И для этого вам нужно снова, явно переопределить удаленную виртуальную функцию. Поэтому, поскольку вам все равно необходимо переопределить его, совершенно очевидно, что вам нужно явно переопределить его в прототипе. Функция по-прежнему удаляется в противном случае.
Для конкретного примера: скажем, у вас есть List.hpp, List.cpp и main.cpp
В List.hpp у вас есть абстрактный класс и обычный класс, который наследуется от абстрактного класса. В основном вы #include "List.hpp"
, а не List.cpp, правильно? Таким образом, у компилятора нет IDEA, что в этом файле (пока он не попытается его скомпилировать.) Если у вас нет переопределенной виртуальной функции, компилятор думает, что вы просто пытаетесь создать экземпляр абстрактного класса и выдает ошибку.
С другой стороны, если вы компилируете List.cpp, компилятор также выдаст ошибку, на этот раз жалуясь, что функция, которую вы пытаетесь написать, на самом деле не определена. Потому что Base::deletedFunction()
отличается от Derived::deletedFunction()
.
Ответ 4
Да, весь смысл чистой виртуальной функции заключается в обеспечении того, чтобы вы переопределяли ее в производном классе; это объявление должно быть явным в С++