Статья: Классы: копирование и присваивание
Написание конструктора копий является чрезвычайно ответственным поступком. Явное определение конструктора копий вызывает изменения в работе программы. Пока мы не пытались переопределить конструктор копий, исправно работал конструктор, порождаемый компилятором автоматически.
Этот конструктор создавал "фотографические" копии объектов, то есть копировал значения абсолютно всех данных-членов, в том числе и ненулевые значения указателей, представляющие адреса динамических областей памяти.
С момента появления переопределённой версии конструктора копий, вся работа по реализации алгоритмов копирования возлагается на программиста. Впрочем, заставить конструктор копий копировать объекты совсем несложно. Создадим класс, описывающий точку на плоскости.
class POINT
{
public:
POINT() { X=0; Y=0; } //конструктор по умолчанию
POINT(int a, int b) { X=a; Y=b; } //еще конструктор
POINT(const POINT& Pixel) { X=Pixel.X; Y=Pixel.Y; } //конструктор
//копирования
int X; //координаты точки
int Y;
};
Как видим, этот конструктор копий просто копирует значения координат. В принципе, если бы мы его не определили, то компилятор создал бы его сам, причем в этом случае он делал бы то же самое. Но конструктор, создающий подобные копии объектов, скорее всего, окажется непригодным для работы с объектами, содержащими в качестве членов указатели или ссылки.
Предполо-жим, что класс содержит указатели. Тогда адреса, содержащиеся в указате-лях объекта-оригинала и объекта-копии, будут идентичны. Это означает, что два объекта будут указывать на одну и ту же область памяти, что, как прави-ло, очень опасно. Это мы рассмотрим подробно несколько позднее.
В переопределяемом конструкторе копий (а в классе он может быть только один) можно реализовывать разнообразные алгоритмы распределения памяти. Здесь всё зависит от программиста.
Итак, обычно, конструктор копий, созданный компилятором, удовлетворителен при следующих обстоятельствах:
Среди членов класса нет указателей (*).
Среди членов класса нет ссылок (&).
В этом случае вполне разумно использовать конструктор, построенный компилятором. В текст определения класса в этом случае полезно поместить соответст-вующий комментарий о том, что конструктор копии не определен вполне сознательно. Вообще говоря, комментарии относи-тельно рассматриваемых четырех членов уместны в каждом классе.
Вот пример:
class X
{
public:
Х(); // конструктор по умолчанию
virtual ~X(); // виртуальный деструктор
// Конструктор копии и операция присваивания не определены
// намеренно. Класс содержит только данные, размещаемые
// в стеке, поэтому предопределенных конструктора копий