Почему имеет смысл дать определение чистой виртуальной функции?
Скотт сказал на Effective С++, 3rd Edition, pg. 43 что для создания абстрактного класса нам просто нужно дать ему чистый виртуальный деструктор:
class AWOV { // AWOV = "Abstract w/o Virtuals"
public:
virtual ~AWOV() = 0; // declare pure virtual destructor
};
Затем он продолжал говорить, что есть один поворот: мы должны предоставить определение для чистого виртуального деструктора:
AWOV::~AWOW() {} // definition of pure virtual dtor
Мой вопрос состоит в том, что, указав = 0
, для чистых виртуальных функций, мы говорим, что функция не может иметь никакого определения для класса, в котором объявлена эта чистая виртуальная функция.
Почему это нормально, чтобы дать определение (даже пустое) для чистого виртуального деструктора здесь?
Ответы
Ответ 1
"мы говорим, что функция не может иметь никакого определения для класса, в котором объявлена эта чистая виртуальная функция.
Это не то, что означает чистый виртуальный. Чистая виртуальная только означает, что содержащий класс не может быть создан (абстрактно), поэтому он должен быть подклассом, а подклассы должны переопределять метод. Например.
struct A {
virtual ~A() = 0;
};
A::~A() {}
struct B : A {};
int main()
{
A a; // error
B b; // ok
}
Здесь деструктор B
неявно определен. Если это был другой метод, который является чисто виртуальным, вам придется явно переопределить его:
struct A {
virtual void foo() = 0;
};
void A::foo() {}
struct B : A {};
int main()
{
B b; // error
}
Предоставление определения для чистого виртуального метода желательно, когда базовый класс должен быть абстрактным, но по-прежнему обеспечивать определенное поведение по умолчанию.
В конкретном случае деструктора он должен быть предоставлен, потому что он будет вызываться автоматически, когда экземпляры подкласса будут уничтожены. Программа, которая пытается создать экземпляр подкласса класса с чистым виртуальным деструктором без определения, не будет передавать компоновщик.
Ответ 2
Создание чистых производных (не абстрактных) классов для реализации своих собственных.
Предоставление реализации позволяет производным классам вызывать поведение базового класса (какие деструкторы выполняют по умолчанию).
Ответ 3
Есть 2 случая.
Чистый виртуальный деструктор
Этот случай специально рассматривается стандартом.
12.4 Деструкторы [class.dtor]
9) Деструктор может быть объявлен virtual
(10.3) или чистым virtual
(10.4); если какие-либо объекты этого класса или любые производный класс создаются в программе, деструктор должен быть определен. Если класс имеет базовый класс с виртуальный деструктор, его деструктор (независимо от того, объявлен ли пользователь или неявно) является виртуальным.
Случай деструктора отличается от того, что все деструкторы вызываются в иерархии наследования (при условии правильного удаления) в обратном порядке построения, даже если это явно не указано. Таким образом, деструктор базового класса вызывается, когда объект удаляется - для чего ему нужна реализация.
Чистый виртуальный метод
Они отличаются от деструкторов тем, что они не требуются для реализации, и им не нужна реализация. Разница в недостающем требовании заключается в том, что при вызове Derived::foo()
он автоматически не вызывает Base::foo()
(не так, как мог, поскольку он может или не может быть реализован).
Почему вы хотите реализовать чистый метод virtual
, зависит от случая. Я рассматриваю чистый спецификатор как намек на программиста, а не на логику. Он сообщает вам - программисту - , что вы должны реализовать этот метод. На самом деле не имеет значения, имеет ли базовый класс реализацию или нет.
by specificiying = 0, для чистых виртуальных функций мы говорим, что функция не может иметь никакого определения для класса, в котором объявлена эта чистая виртуальная функция.
Не совсем. Вы говорите, что производные не-абстрактные классы должны переопределять эту функцию. Это не мешает вам реализовать его самостоятельно.
Ответ 4
Это не обязательно для всех чистых виртуальных функций. Не за что.
Таким образом, производные классы будут по-прежнему вынуждены переопределять реализацию, но в базовом классе будет реализована реализация по умолчанию , если вам нужно ее называть. > . И этот случай здесь - потому что вы имеете дело с деструктором: когда производный объект уничтожается, его деструктор вызывается и вызываются его деструкторы его базовых классов. Для этого вам нужна реализация для A::~A
.
Ответ 5
Используя функцию pure virtual, мы вынуждаем пользователя класса заменять функцию другим в производном классе.
Функцию базового класса можно вызвать с помощью BaseClass::myfunction(...)
Теперь базовый класс может захотеть предоставить некоторые основные функции, которые может использовать производный класс, если он захочет сделать это.