vector v2 = 10; // ошибка: конструктор, получающий размер,

                     // является явным

void f(vector); // параметр f() инициализируется копией

f(10); // ошибка: нельзя использовать явный конструктор для

       // копирования аргумента

f(vector(10));  // ok: непосредственно создать временный вектор

                     // из int

Прямая инициализация вектора v1 корректна, но на первый взгляд эквивалентная инициализация копией вектора v2 ошибочна, поскольку конструктор вектора, получающий один параметр размера, является явным. По тем же причинам недопустима инициализация копией вектора v2 — нельзя неявно использовать явный конструктор при передаче аргумента или возвращении значения из функции. Если нужно использовать явный конструктор, то сделать это следует явно, как в последней строке примера, приведенного выше.

Компилятор может обойти конструктор копий

Во время инициализации копией компилятору можно (но не обязательно) пропустить конструктор копий или перемещения и создать объект непосредственно. Таким образом, код

string null_book = "9-999-99999-9"; // инициализация копией

компилятор может выполнить так:

string null_book("9-999-99999-9"); // компилятор пропускает конструктор

                                   // копий

Но даже если компилятор обойдет вызов конструктора копий или перемещения, то он все равно должен существовать и быть доступен (не должен быть закрытым, например) в этой точке программы.

Упражнения раздела 13.1.1

Упражнение 13.1. Что такое конструктор копий? Когда он используется?

Упражнение 13.2. Объясните, почему следующее объявление недопустимо:

Sales_data::Sales_data(Sales_data rhs);

Упражнение 13.3. Объясните, что происходит при копировании объектов классов StrBlob и StrBlobPtr?

Упражнение 13.4. Предположим, класс Point имеет открытый конструктор копий. Укажите каждый случай использования конструктора копий в этом фрагменте кода:

Point global;

Point foo_bar(Point arg) {

 Point local = arg, *heap = new Point(global);

 *heap = local;

 Point pa[4] = { local, *heap };

 return *heap;

}

Упражнение 13.5. Напишите с учетом следующего эскиза класса конструктор копий, копирующий все переменные-члены. Конструктор должен динамически резервировать новую строку (см. раздел 12.1.2) и копировать объект, на который указывает ps, а не сам указатель ps.

class HasPtr {

public:

 HasPtr(const std::string &s = std::string()) :

  ps(new std::string(s)), i(0) { }

private:

 std::string *ps;

 int i;

};

<p><image l:href="#reader.png"/>13.1.2. Оператор присвоения копии</p>

Подобно тому, как класс контролирует инициализацию своих объектов, он контролирует также присваивание своих объектов:

Sales_data trans, accum;

trans = accum; // использует оператор присвоения копии

               // класса Sales_data

Компилятор сам синтезирует оператор присвоения копии, если он не определен в классе явно.

Перегруженный оператор присвоения

Прежде чем перейти к синтезируемому оператору присвоения, необходимо ознакомиться с перегрузкой операторов (overloaded operator), подробно рассматриваемой в главе 14.

Перегруженные операторы — это функции, имена которых состоят из слова operator и символа определяемого оператора. Следовательно, оператор присвоения — это функция operator=. Подобно любой другой функции, у функции оператора есть тип возвращаемого значения и список параметров.

Параметрами перегруженного оператора являются его операнды. Некоторые операторы, например присвоение, должны быть определены, как функции-члены. Когда оператор является функцией-членом, левый операнд связан с неявным параметром this (см. раздел 7.1.2). Правый операнд бинарного оператора, такого как присвоение, передается как явный параметр. Оператор присвоения копии получает аргумент того же типа, что и класс:

class Foo {

public:

 Foo& operator=(const Foo&); // оператор присвоения

 // ...

};

Для совместимости с оператором присвоения встроенных типов (см. раздел 4.4) операторы присвоения обычно возвращают ссылку на свой левый операнд. Следует также заметить, что библиотека обычно требует от типов, хранимых в контейнере, наличия операторов присвоения, возвращающих ссылку на левый операнд.

Перейти на страницу:

Похожие книги