Полиморфный класс должен подавлять открытое копирование/перемещение
Причина
Полиморфный класс — это класс, который определяет или наследует по крайней мере одну виртуальную функцию. Вероятно, он будет использоваться как базовый класс для других производных классов с полиморфным поведением. Если он случайно передается по значению с неявно генерируемым конструктором копирования и присваиванием, мы рискуем срезанием: будет скопирована только базовая часть производного объекта, и полиморфное поведение будет повреждено.
Если класс не имеет данных, =delete функции копирования/перемещения. В противном случае сделайте их protected.
Плохой пример
class B { // ПЛОХО: полиморфный базовый класс не подавляет копирование
public:
virtual char m() { return 'B'; }
// ... ничего о операциях копирования, поэтому использует по умолчанию ...
};
class D : public B {
public:
char m() override { return 'D'; }
// ...
};
void f(B& b)
{
auto b2 = b; // упс, срезает объект; b2.m() вернет 'B'
}
D d;
f(d);
Пример
class B { // ХОРОШО: полиморфный класс подавляет копирование
public:
B() = default;
B(const B&) = delete;
B& operator=(const B&) = delete;
virtual char m() { return 'B'; }
// ...
};
class D : public B {
public:
char m() override { return 'D'; }
// ...
};
void f(B& b)
{
auto b2 = b; // хорошо, компилятор обнаружит непреднамеренное копирование и возразит
}
D d;
f(d);
Примечание
Если вам нужно создать глубокие копии полиморфных объектов, используйте функции clone(): см. C.130.
Исключение
Классы, которые представляют объекты исключений, должны быть одновременно полиморфными и копируемыми конструктором.
Применение
- Отметьте полиморфный класс с открытой операцией копирования.
- Отметьте присваивание объектов полиморфного класса.
C.other: Другие правила операции по умолчанию
В дополнение к операциям, для которых язык предлагает реализации по умолчанию, есть несколько операций, которые настолько фундаментальны, что требуют специальных правил для их определения: сравнения, swap и hash.