Автор: Никита
Головной раздел: Меню
Билет 3. Конструкторы и деструктор класса, конструктор копирования и конструктор перемещения, назначение, пример.
Конструктор - блок инструкций, вызываемый при создании объекта класса.
Деструктор - блок инструкций, вызываемый при уничтожении объекта класса.
Оба не имеют возвращаемых значений. Оба могут определяться как внутри класса, так и вне его
Назначение конструктора: присвоение каких-то значений полям, выделение памяти, открытие файлов и установление сетевых соединений.
Параметры конструктора. Конструктор может принимать какие-то значения в качестве аргументов - например, для установки значений полям. Также возможно создание нескольких конструкторов с разными параметрами. Деструктор всегда один и без параметров.
Имя_класса(Список_формальных_параметров){
Операторы_тела конструктора
}
~Имя_класса(){
Операторы_тела деструктора
}
A *pA1 = new A; //Без параметров, в куче
A *pA2 = new A(42,69); //С двумя параметрами, в куче
A pA3(); //С одним параметром
A pA4 = 1; //Такая формулировка возможна, если у класса есть конструктор с одним параметром.
//В этом случае эта строчка идентична предыдущей.
Чтобы исключить вызов конструктора через присваивание, как показано в последнем примере, к конструктору дописывается ключевое слово explicit (перед конструктором).
Для конструктора, конструкторов копирования и перемещения, а также деструктора справедливо следующее: если программист не написал их сам, то компилятор допишет их за него. Такие конструкторы(деструкторы) называются неявными. Также важно понимать, что конструктор, декструтор, к.копирования и к.перемещения должны иметь доступ модификатор доступа public.
Это конструктор вида (для случая внутри класса):
A(const A& a){ //A - имя класса
Операторы_тела конструктора
}
Он обязательно принимает в качестве аргумента ссылку на другой объект того же класса. Если программист пожелает, то конструктор может начать принимать что-то ещё.
Назначение конструктора копирования: копирование всех полей одного объекта в другой (по умолчанию). При переопределении может вытворять всё, что пожелает программист. Например, менять поля местами.
Благодаря этому конструктору, мы можем, например, писать вот так:
A a1;
A a2(a1); //Конструктор копирования
A a3=a1; //Равносильно предыдущей строке
В данном примере для a2 и a3 будет вызван конструктор копирования, который скопирует каждое поле a1.
Самое главное про конструктор копирования: если вы оставили для полей-указателей простое копирование, то, когда в первом объекте (который мы копировали) они будут почищены (например, деструктором), во втором они также почистятся, а этого вы, скорее всего, не задумываете.
Если мы захотим сломать конструктор копирования, указав явно только один его вариант, который принимает не только ссылку, но и другие аргументы, то программа сама додумает за нас самый просто конструктор копирования с единственным аргументом (ссылкой). И пример, приведённый выше, всё ещё будет работать. А вот если мы сами напишем конструктор копирования с одним аргументом (ссылкой) и добавим к нему слово explicit, то пример работать перестанет, так как из-за третьей строчки программа не скомпилируется.
Также обратите внимание, что переопределив конструктор копирования вы никак не затронете обычные операции присваивания.
A b;
A a1 = b; //Конструктор копирования (не explicit)
A a2; //Обычный конструктор
a2 = b; //Присваивание
Если мы переопределили конструктор копирования, чтобы он, например, менял местами поля и дописывал всякие нехорошие слова к полям-строкам, а затем запустили пример, приведённый выше, то эти действия произведутся только для a1, а объект a2 будет идентичен объекту b.
Это конструктор вида (для случая внутри класса):
A(A&& a){ //A - имя класса
Операторы_тела конструктора
}
Назначение конструктора перемещения: взять поля в исходном объекте и перекинуть в новый так, чтобы исходный можно было свободно уничтожить, не повредив новый. Пример реализации - скопировать поля в новый и занулить указатели в исходном, чтобы его деструктор не добрался до важных объектов.
Вызов конструктора перемещения в коде программы:
A a1;
A a2 = std::move(a1);