В отличие от конструкторов и операторов присвоения, деструктор несет ответственность только за освобождение ресурсов, зарезервированных производным классом. Помните, что члены объекта освобождаются неявно (см. раздел 13.1.3). Точно так же часть базового класса объекта производного класса освобождается автоматически.
При определении конструктора копии или перемещения (см. раздел 13.1.1 и раздел 13.6.2) для производного класса обычно используется соответствующий конструктор базового класса, инициализирующий базовую часть объекта:
class Base { /* ... */ };
class D: public Base {
public:
//
//
//
//
//
D(const D& d) : Base(d) //
/*
D(D&& d): Base(std::move(d)) //
/*
};
Инициализатор Base(d)
передает объект класса D
конструктору базового класса. Хотя в принципе у класса Base
может быть конструктор с параметром типа D
, на практике это очень маловероятно. Вместо этого инициализатор Base(d)
будет (обычно) соответствовать конструктору копий класса Base
. В этом конструкторе объект d
будет связан с параметром типа Base&
. Конструктор копий класса Base
скопирует базовую часть объекта d
в создаваемый объект. Будь инициализатор для базового класса пропущен, для инициализации базовой части объекта класса D
будет использован стандартный конструктор класса Base
.
//
//
D(const D& d) /*
{ /* ... */ }
Предположим, что конструктор класса D
копирует производные члены объекта d
. Этот вновь созданный объект был бы настроен странно: его члены класса Base
содержали бы значения по умолчанию, в то время как его члены класса D
были бы копиями данных из другого объекта.
Подобно конструктору копирования и перемещения, оператор присвоения производного класса (см. раздел 13.1.2 и раздел 13.6.2) должен присваивать свою базовую часть явно:
//
D &D::operator=(const D &rhs) {
Base::operator=(rhs); //
//
//
return *this;
}
Этот оператор начинается с явного вызова оператора присвоения базового класса, чтобы присвоить члены базовой части объекта производного. Оператор базового класса (по-видимому, правильно) отработает случай присвоения себя себе и, если нужно, освободит прежнее значение в базовой части левого операнда и присвоит новое значение правой. По завершении работы оператора продолжается выполнение всего необходимого для присвоения членов в производном классе.
Следует заметить, что конструктор или оператор присвоения производного класса может использовать соответствующую функцию базового класса независимо от того, определил ли базовый класс собственную версию этого оператора или использует синтезируемую. Например, вызов оператора Base::operator=
выполняет оператор присвоения копии в классе Base
. При этом несущественно, определяется ли этот оператор классом Base
явно или синтезируется компилятором.