Деструкторы базовых классов — важное исключение из эмпирических правил, согласно которым, если класс нуждается в деструкторе, то он также нуждается в функциях копирования и присвоения (см. раздел 13.6). Базовый класс почти всегда нуждается в деструкторе, поэтому он может сделать деструктор виртуальным. Если базовый класс обладает пустым деструктором, только чтобы сделать его виртуальным, то наличие у класса деструктора вовсе не означает, что также необходим оператор присвоения или конструктор копий.
Тот факт, что базовый класс нуждается в виртуальном деструкторе, имеет важное косвенное последствие для определения базовых и производных классов: если класс определит деструктор (даже с использованием синтаксиса = default
, чтобы использовать синтезируемую версию), то компилятор не будет синтезировать функцию перемещения для этого класса (см. раздел 13.6.2).
Упражнение 15.24. Какие виды классов нуждаются в виртуальном деструкторе? Какие задачи должен выполнять виртуальный деструктор?
Синтезируемые функции-члены управления копированием в базовом или производном классе выполняются, как любой другой синтезируемый конструктор, оператор присвоения или деструктор: они почленно инициализируют, присваивают или удаляют члены самого класса. Кроме того, эти синтезируемые члены инициализируют, присваивают или удаляют прямую базовую часть объекта при помощи соответствующей функции базового класса. Соответствующие примеры приведены ниже.
• Синтезируемый стандартный конструктор класса Bulk_quote
запускает стандартный конструктор класса Disc_quote
, который в свою очередь запускает стандартный конструктор класса Quote
.
• Стандартный конструктор класса Quote
инициализирует по умолчанию переменную-член bookNo
пустой строкой и использует внутриклассовый инициализатор для инициализации переменной-члена price
нулем.
• Когда конструктор класса Quote
завершает работу, конструктор класса Disc_quote
продолжает ее, используя внутриклассовые инициализаторы для инициализации переменных qty
и discount
.
• Когда завершает работу конструктор класса Disc_quote
, конструктор класса Bulk_quote
продолжает ее, но не выполняет никаких других действий.
Точно так же синтезируемый конструктор копий класса Bulk_quote
использует (синтезируемый) конструктор копий класса Disc_quote
, который использует (синтезируемый) конструктор копий класса Quote
. Конструктор копий класса Quote
копирует переменные-члены bookNo
и price
; а конструктор копий класса Disc_quote
копирует переменные-члены qty
и discount
.
Следует заметить, что не имеет значения, синтезируется ли функция-член базового класса (как в случае иерархии Quote
) или имеет предоставленное пользователем определение. Важно лишь то, что соответствующая функция-член доступна (см. раздел 15.5) и что она не удаленная.
Каждый из классов иерархии Quote
использует синтезируемый деструктор. Производные классы делают это неявно, тогда как класс Quote
делает это явно, определяя свой (виртуальный) деструктор как = default
. Синтезируемый деструктор (как обычно) пуст, и его неявная часть удаляет члены класса (см. раздел 13.1.3). В дополнение к удалению собственных членов фаза удаления деструктора в производном классе удаляет также свою прямую базовую часть. Этот деструктор в свою очередь вызывает деструктор своего прямого базового класса, если он есть. И так далее до корневого класса иерархии.
Как уже упоминалось, у класса Quote
нет синтезируемых функций перемещения, поскольку он определяет деструктор. При каждом перемещении объекта Quote
(см. раздел 13.6.2) будут использоваться (синтезируемые) функции копирования. Как будет продемонстрировано ниже, тот факт, что у класса Quote
нет функций перемещения, означает, что его производные классы также не будут их иметь.
Синтезируемый стандартный конструктор или любая из функций-членов управления копированием базового либо производного класса может быть определена как удаленная по тем же причинам, что и в любом другом классе (см. раздел 13.1.6 и раздел 13.6.2). Кроме того, способ определения базового класса может вынудить член производного класса стать удаленным.
• Если стандартный конструктор, конструктор копий, оператор присвоения копии или деструктор в базовом классе удалены или недоступны (раздел 15.5), то соответствующая функция-член в производном классе определяется как удаленная, поскольку компилятор не может использовать функцию-член базового класса для создания, присвоения или удаления части объекта базового класса.