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

Почему мне нужно повторно объявить переопределенные функции в производных классах в С++?

Предположим, что у меня есть следующий код:

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. Это проблема с визуальной студией или она соблюдается стандартами С++?

4b9b3361

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

Да, весь смысл чистой виртуальной функции заключается в обеспечении того, чтобы вы переопределяли ее в производном классе; это объявление должно быть явным в С++