Почему имеет смысл дать определение чисто виртуальной функции?

Скотт сказал на Effective C ++, 3-е издание, стр. 43 что для создания абстрактного класса нам просто нужно дать ему чистый виртуальный деструктор:

class AWOV {                  // AWOV = "Abstract w/o Virtuals"public:
virtual ~AWOV() = 0;        // declare pure virtual destructor
};

Затем он сказал, что есть один поворот: мы должны дать определение чисто виртуальному деструктору:

AWOV::~AWOW() {}              // definition of pure virtual dtor

Мой вопрос, указав = 0для чисто виртуальных функций мы говорим, что функция не может иметь никакого определения для класса, где объявлена ​​эта чисто виртуальная функция.

Почему нормально давать определение (даже пустое) для чистого виртуального деструктора?

20

Решение

«мы говорим, что функция не может иметь никакого определения для класса, где объявлена ​​эта чисто виртуальная функция».

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

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
}

Предоставление определения для чисто виртуального метода желательно, когда базовый класс должен быть абстрактным, но все же обеспечивать некоторое поведение по умолчанию.

В конкретном случае деструктора это имеет быть обеспеченным, потому что он будет вызван автоматически когда экземпляры подкласса уничтожены. Программа, которая пытается создать экземпляр подкласса класса с помощью чистого виртуального деструктора без определения, не пропустит компоновщик.

10

Другие решения

Делая это чисто, заставляет производные (неабстрактные) классы реализовывать свои собственные.

Предоставление реализации позволяет производным классам вызывать поведение базового класса (что по умолчанию делают деструкторы).

6

Есть 2 случая.

Чистый виртуальный деструктор

Этот случай специально рассматривается стандартом.

12.4 Деструкторы [class.dtor]

9) Деструктор может быть объявлен virtual (10.3) или чистый virtual (10.4); если какие-либо объекты этого класса или любой
Производный класс создается в программе, деструктор должен быть определен. Если класс имеет базовый класс с
виртуальный деструктор, его деструктор (объявленный пользователем или неявно) виртуальный.

Случай деструктора отличается, потому что все деструкторы вызываются в иерархии наследования (при условии правильного удаления) в обратном порядке построения, даже если не явно. Таким образом, деструктор базового класса вызывается, когда объект удаляется — поэтому он нуждается в реализации.

Чистый виртуальный метод

Они отличаются от деструкторов тем, что их не нужно реализовывать, и при этом они не нуждаются в реализации. Разница в отсутствии требования заключается в том, что когда Derived::foo() вызывается, он не вызывает автоматически Base::foo() (не то, чтобы это могло, так как это может или не может быть реализовано).

Почему вы хотите реализовать чистый virtual Метод зависит от случая. Я рассматриваю чистый спецификатор как подсказку для программиста, а не как связанную с логикой. Это говорит вам — программист — что вы должны реализовать этот метод. Не имеет значения, имеет ли базовый класс реализацию или нет.

указав = 0 для чисто виртуальных функций, мы говорим, что функция не может иметь никакого определения для класса, в котором объявлена ​​эта чисто виртуальная функция.

На самом деле, нет. Вы говорите, что производные неабстрактные классы должны переопределять эту функцию. Это не мешает вам реализовать это самостоятельно.

5

Это не обязательно для всех чисто виртуальный функции. Не за что.

Таким образом, производные классы будут все равно будет вынужден переопределить реализацию, но в базовом классе будет реализация по умолчанию, если ты необходимость называть это. И это здесь — потому что вы имеете дело с деструктором: когда производный объект уничтожается, его деструктор называется и его базовые классы деструкторы также называются. Вот почему вам нужна реализация для A::~A,

2

Делая функцию чисто виртуальной, мы заставляем пользователя класса заменить функцию другой в производном классе.

Функция базового класса все еще может быть вызвана с BaseClass::myfunction(...)

Теперь базовый класс может захотеть предоставить некоторые основные функциональные возможности, которые может использовать производный класс, если он решит это сделать.

0
По вопросам рекламы [email protected]