• Если у базового класса недоступен или удален деструктор, то синтезируемые стандартный конструктор и конструктор копий в производных классах определяются как удаленные, поскольку нет никакого способа удалить базовую часть производного объекта.
• Как обычно, компилятор не будет синтезировать удаленную функцию перемещения. Если использовать синтаксис = default
для создания функции перемещения, то это будет удаленная функция в производном классе, если соответствующая функция в базовом классе будет удалена или недоступна, поскольку часть базового класса не может быть перемещена. Конструктор перемещения также будет удален, если деструктор базового класса окажется удален или недоступен.
Для примера рассмотрим базовый класс В
:
class B {
public:
B();
B(const B&) = delete;
//
};
class D : public B {
//
};
D d; //
//
D d2(d); //
D d3(std::move(d)); //
//
Класс имеет доступный стандартный конструктор и явно удаленный конструктор копий. Поскольку конструктор копий определяется, компилятор не будет синтезировать для класса В
конструктор перемещения (см. раздел 13.6.2). В результате невозможно ни переместить, ни скопировать объекты типа В
. Если бы класс, производный от типа В
, хотел позволить своим объектам копирование или перемещение, то этот производный класс должен был бы определить свои собственные версии этих конструкторов. Конечно, этот класс должен был бы решить, как скопировать или переместить члены в эту часть базового класса. Практически, если у базового класса нет стандартного конструктора копий или конструктора перемещения, то его производные классы также обычно не будут их иметь.
Как уже упоминалось, большинство базовых классов определяет виртуальный деструктор. В результате по умолчанию базовые классы вообще не получают синтезируемых функций перемещения. Кроме того, по умолчанию классы, производные от базового класса, у которого нет функций перемещения, также не получают синтезируемых функций перемещения.
Поскольку отсутствие функции перемещения в базовом классе подавляет синтез функций перемещения в его производных классах, базовые классы обычно должны определять функции перемещения, если это имеет смысл. Наш класс Quote
может использовать синтезируемые версии. Однако класс Quote
должен определить эти члены явно. Как только он определит собственные функции перемещения, он должен будет также явно определить версии копирования (см. раздел 13.6.2):
class Quote {
public:
Quote() = default; //
Quote(const Quote&) = default; //
Quote(Quote&&) = default; //
Quote& operator=(const Quote&) = default; //
Quote& operator=(Quotes&) = default; //
virtual ~Quote() = default;
//
};
Теперь объекты класса Quote будут почленно копироваться, перемещаться, присваиваться и удаляться. Кроме того, классы, производные от класса Quote
, также автоматически получат синтезируемые функции перемещения, если у них не будет членов, которые воспрепятствуют перемещению.
Упражнение 15.25. Зачем определять стандартный конструктор для класса Disc_quote
? Как повлияет на поведение класса Bulk_quote
, если вообще повлияет, удаление этого конструктора?
Как упоминалось в разделе 15.2.2, фаза инициализации конструктора производного класса инициализирует часть (части) базового класса производного объекта наряду с инициализацией его собственных членов. В результате конструкторы копирования и перемещения для производного класса должны копировать и перемещать члены своей базовой части наравне с производной. Точно так же оператор присвоения производного класса должен присваивать члены базовой части производного объекта.