Этой частью мы завершим начатое в статьях "Элементы класса, о которых всегда необходимо помнить" и "Классы: копирование и присваивание. Часть 1, Часть 2 и Часть3" подробное рассмотрение проблемы копирования и присваивания в классах.
В этой части мы рассмотрим как можно заблокировать копирование и присваивание, как можно реализовать копирование через присваивание, и обсудим проблемы копирования в производных (дочерних, а может сыновних?) классах.
Блокирование копирования и присваивания
Издержки на размещение в памяти копирование и воспроизведение простых типов данных в принципе невелики. Чем сложнее тип данных, тем больше будут "расходы" на копирование объектов этого типа. Сложные типы могут требовать нетривиального управления памятью, они могут выполнять сложные графические преобразования, могут состоять из сложных структур данных, например, связанных списков, бинарных деревьев и мультимножеств; могут отвечать за инициализацию внешних устройств или быть элементами разветвленной иерархии.
Как и в большинстве вопросов конкретной реализации, именно вам придется решать, в каких обстоятельствах целесообразно заблокировать копирование.
Мы же посмотрим только как это сделать. Чтобы запретить компилятору автоматически создавать конструктор копий и операцию присваивания, надо объявить их в классе, но не писать определение (метод или функцию). При этом объявление должно располагаться в закрытой (private) секции класса.
class POINT
{
public:
// открытые члены
protected:
// защищенные члены
private:
// закрытые члены
POINT(const POINT&);
POINT& operator=(const POINT&);
// блокировка копирования
};
Для произвольного класса POINT объявление без определения (тело функции отсутствует, его просто не надо писать) блокирует копирование, заставляя компилятор генерировать сообщение об ошибке при вызове одной из этих функций. Этот прием запрещает копирование отдельных объектов, не лишая, однако, вас возможности использовать псевдонимы (псевдонимом (если вы забыли) может быть, например, имя аргумента, через который передается ссылка на объект).
Вряд ли вам придется слишком часто пользоваться этим приемом, но он станет хорошим дополнением к вашим возможностям на тот случай, когда вам потребуется что-то из ряда вон выходящее. В большинстве случаев, конечно же, копирование должно быть разрешено: для простых классов без динамических данных - буквальное, а для классов с динамическими данными - развернутое.