Шрифт:
Интервал:
Закладка:
18.3. Основные операции

• Конструкторы с одним или несколькими аргументами.
• Конструктор по умолчанию.
• Копирующий конструктор (копирование объектов одинаковых типов).
• Копирующее присваивание (копирование объектов одинаковых типов).
• Деструктор.
Обычно класс должен иметь один или несколько конструкторов, аргументы которых инициализируют объект.
string s(" Триумф "); // инициализируем объект s строкой "Триумф"
vector<double> v(10); // создаем вектор v, состоящий из 10 чисел
// double
Как видим, смысл и использование инициализатора полностью определяются конструктором. Стандартный конструктор класса string использует в качестве начального значения символьную строку, а стандартный конструктор класса vector в качестве параметра получает количество элементов. Обычно конструктор используется для установки инварианта (см. раздел 9.4.3). Если мы не можем определить хороший инвариант для класса, то, вероятно, плохо спроектировали класс или структуру данных.
Конструкторы, имеющие аргументы, сильно зависят от класса, в котором они реализованы. Остальные операции имеют более или менее стандартную структуру.
Как понять, что в классе необходим конструктор по умолчанию? Он требуется тогда, когда мы хотим создавать объекты класса без указания инициализатора. Наиболее распространенный пример такой ситуации возникает, когда мы хотим поместить объекты класса в стандартный контейнер, имеющий тип vector. Приведенные ниже инструкции работают только потому, что для типов int, string и vector<int> существуют значения, предусмотренные по умолчанию.
vector<double> vi(10); // вектор из 10 элементов типа double,
// каждый из них инициализирован 0.0
vector<string> vs(10); // вектор из 10 элементов типа string,
// каждый из них инициализирован ""
vector<vector< int> > vvi(10); // вектор из 10 векторов,
// каждый из них
// инициализирован конструктором vector()
Итак, иметь конструктор по умолчанию часто бывает полезно. Возникает следующий вопрос: а когда именно целесообразно иметь конструктор по умолчанию? Ответ: когда мы можем установить инвариант класса с осмысленным и очевидным значением по умолчанию. Для числовых типов, таких как int и double, очевидным значением является 0 (для типа double оно принимает вид 0.0). Для типа string очевидным выбором является "". Для класса vector можно использовать пустой вектор. Если тип T имеет значение по умолчанию, то оно задается конструктором T(). Например, double() равно 0.0, string() равно "", а vector<int>() — это пустой vector, предназначенный для хранения переменных типа int.




18.3.1. Явные конструкторы
Конструктор, имеющий один аргумент, определяет преобразование типа этого аргумента в свой класс. Это может оказаться очень полезным. Рассмотрим пример.
class complex {
public:
complex(double); // определяет преобразование double в complex
complex(double,double);
// ...
};
complex z1 = 3.18; // OK: преобразует 3.18 в (3.18,0)
complex z2 = complex(1.2, 3.4);

class vector {
// ...
vector(int);
// ...
};
vector v = 10; // создаем вектор из 10 элементов типа double
v = 20; // присваиваем вектору v новый вектор
// из 20 элементов типа double to v
void f(const vector&);
f(10); // Вызываем функцию f с новым вектором,
// состоящим из 10 элементов типа double

class vector {
// ...
explicit vector(int);
// ...
};
vector v = 10; // ошибка: преобразования int в vector нет
v = 20; // ошибка: преобразования int