Однако в том, что компилятор не будет синтезировать стандартный конструктор для класса со ссылочным или с константным членом, который не может быть создан стандартно, ничего удивительного нет. Нет ничего удивительного и в том, что класс с константным членом не может использовать синтезируемый оператор присвоения копии: в конце концов, этот оператор пытается присвоить значения всем членам классов. Однако присвоить новое значение константному объекту невозможно.
Хотя вполне возможно присвоить новое значение ссылке, это изменит значение объекта, на который она ссылается. Если бы оператор присвоения копии синтезировался для таких классов, то левый операнд продолжил бы ссылаться на тот же объект, что и перед присвоением. Он не ссылался бы на тот же объект, что и правый операнд. Поскольку это поведение вряд ли будет желательно, синтезируемый оператор присвоения копии определяется как удаленный, если у класса есть ссылочный член.
Как будет продемонстрировано в разделах 13.6.2, 15.7.2 и 19.6, есть и другие аспекты, в связи с которыми функции-члены копирования могут быть определены как удаленные.
До появления нового стандарта классы предотвращали копирование, объявляя свой конструктор копий и оператор присвоения копии как закрытые (private):
class PrivateCopy {
//
//
//
// обычному пользовательскому коду
PrivateCopy(const PrivateCopy&);
PrivateCopy &operator=(const PrivateCopy&);
//
public:
PrivateCopy() = default; //
//
~PrivateCopy(); //
//
};
Поскольку деструктор является открытым (public), пользователи смогут определять объекты класса PrivateCopy. Но так как конструктор копий и оператор присвоения копии являются закрытыми (private), пользовательский код не сможет копировать такие объекты. Но дружественные классы и члены класса вполне могут создавать копии. Чтобы предотвратить копирование и друзьями, и членами класса, эти функции-члены объявляют закрытыми и не определяют их.
За одним исключением, рассматриваемым в разделе 15.2.1, вполне допустимо объявлять, но не определять функции-члены (см. раздел 6.1.2). Попытка использования неопределенной функции-члена приведет к отказу во время компоновки. При объявлении (без определения) закрытого конструктора копий можно предотвратить любую попытку скопировать объект класса: пользовательский код, пытающийся сделать копию, будет помечен как ошибочный во время компиляции; попытки копирования в функциях-членах или дружественных классах будут отмечены как ошибка во время редактирования.
= delete вместо объявления их закрытыми.
Упражнение 13.18. Определите класс Employee, содержащий имя сотрудника и его уникальный идентификатор. Снабдите класс стандартным конструктором и конструктором, получающим строку, представляющую имя сотрудника. Каждый конструктор должен создавать уникальный идентификатор за счет приращения статической переменной-члена.
Упражнение 13.19. Должен ли класс Employee определить собственные версии функций-членов управления копированием? Если да, то почему? Если нет, то тоже почему? Реализуйте все члены управления копированием, в которых, на ваш взгляд, нуждается класс Employee.
Упражнение 13.20. Объясните, что происходит при копировании, присвоении и удалении объектов классов TextQuery и QueryResult из раздела 12.3.
Упражнение 13.21. Должны ли классы TextQuery и QueryResult определять собственные версии функций-членов управления копированием? Если да, то почему? Если нет, то почему? Реализуйте функции управления копированием, необходимые, по-вашему, в этих классах.