Конструкторы и деструкторы: инициализация объектов

Конструктор

Конструктором называют функцию, которая используется для инициализации объектов класса. Одним из таких классов является date:

class date
{
int day, month, year;
public:
set(int, int, int);
};

Нигде не указывается и не утверждается в обязательной инициализации объектов.

Из-за этого программист может забыть это сделать или выполнить процедуру дважды. На помощь приходит ОПП, что позволит описать функцию, которую программист использует для инициализации объектов. Применяемая функция называется конструктором не просто так. С ее помощью выполняется конструирование значений. Конструктор отличается таким же именем, что и инициализируемый объект, а также отсутствием возвращаемого значения. При конструировании определенного класса все объекты, входящие в состав данного класса, также будут проинициализированными.

class date {
int day, month, year;
public:
date(int, int, int); // конструктор
};

Конструктор может требовать аргументы, поэтому их необходимо предоставить следующим образом:

date today = date(6,4,2014); // полная форма
date xmas(25,12,0); // сокращенная форма
// date my_burthday; // недопустимо, опущена инициализация

Бывают случаи, когда необходимо использовать несколько конструкторов. Это применимо, когда требуется использовать несколько вариантов для инициализации объектов. Например:

class date {
int month, day, year;
public:
date(int, int, int); // день месяц год
date(char*); // дата в строковом представлении
date(); // дата по умолчанию: сегодня
};

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

date july4(«Февраль 27, 2014»);
date guy(27, 2, 2014);
date now; // инициализируется по умолчанию

Эффективным и удобным решением является применение значений по умолчанию. Это позволит свести к минимуму число перезагруженных функций и конструкторов.

Значения по умолчанию

Значением по умолчанию является стандартный конструктор, который не требует параметров. Данное решение может быть двух типов:

  • с пустым списком параметров;
  • с наличием аргументов со значениями по умолчанию.

Конструктивные функции могут являться перезагруженными, а вот конструкторов по умолчанию много не бывает, так как используется только один.

class date
{
int month, day, year;
public:
date(int, int, int);
date(char*);
date(); // конструктор по умолчанию
};

Когда выполняется создание объектов, необходимо вызвать конструктор. К нему не нужно прибегать в случае создания копий разных объектов того же
класса. К примеру:

date date2 = date1;

Но следует выделить другие случаи, когда осуществляется неявное создание объектов без создания конструкторов:

Формальный параметр – функциональный объект, который передается по значению. Его создают в стеке, когда определенная функция вызывается, а затем инициализируется при помощи копии фактического параметра.

Функциональный результат – это объект, который также передается по значению. Он копируется и становится временным объектом, когда выполняется операция return. Это позволяет сохранить результаты функций.

В следующих случаях конструктор не вызывается по причине создания новых объектов:

  1. создание копии объекта в том же классе в виде date2;
    2. когда создается формальный параметр в стеке;
    3. когда выполняется временный объект, который сохраняет значение и возвращается в качестве функции.

Вместо вышеприведенных объектов выполняется копирование содержимого объекта-источника:

  1. из приведенного примера date1;
    2. фактического параметра;
    3. объекта с результатом при помощи оператора return.

Конструктор копии

Когда создаются новые объекты, которые осуществляются на базе уже созданных, то выполняется поверхностное копирование. Другими словами, происходит копирование данных с содержанием объекта-источника. Важно отметить, что такое копирование сопровождается обязательным дублированием динамических переменных, массивов или ссылок при наличии их в источнике для создания новых объектов. Именно для такой ситуации существует конструктор копии.

С его помощью автоматизируется данный процесс, так как он вызывается во всех возможных случаях. Он отличается наличием единственного параметра — ссылки на источник:

class String
{
char *str;
int size;
public:
String(String&); // Конструктор копирования
};
String::String(String& right) { // Создает копии динамических
// переменных и ресурсов
str = new char[right->size];
strcpy(str, right->str);
size = right->size;
}

Деструкторы

Конструктор обеспечивает требуемую инициализацию для определяемого программистом класса. Многие типы нуждаются в обратном процессе. Именно для этого существуют деструкторы, которые способны выполнить очистку указанных объектов. Данная функция характеризуется именем класса со знаком «тильда», который ставится перед ней. Например, деструктор будет иметь имя ~X() для класса Х. Большое количество классов отличаются использованием динамической памяти, которую необходимо выделить конструктором. Чтобы ее освободить, применяется деструктор.

class date
{
int day, year;
char *month;
public:
date(int d, char* m, int y)
{
day = d;
month = new char[strlen(m)+1];
strcpy_s(month, strlen(m)+1,m);
year = y;
}
~date() { delete[] month; } // деструктор
};

Поля с наличием типа класса

Для примера можно взять класс vect, который реализует защищенный массив.

Для каждого используемого такого массива необходимо хранить несколько следующих значений: вес, рост группы мышц и возраст. Создается новый класс, где группируются эти 3 массива.

Для этого применяется конструктор к новому классу, который обладает пустым телом и списком вызываемых конструктивных функций для vect. Перечисление начинается после двоеточия и сопровождается запятыми. Для их выполнения используется целый аргумент i, что позволяет создать 3 объекта: a, b, с.

Члены класса также выполняются с конструкторами, которые функционируют до конструктора класса, так как они описаны в его пределах. Конструктивные функции для членов класса вызываются в порядке их объявления. При необходимости наличия аргументов для членов класса, требуемые объекты необходимо указать с нужными аргументами в списке инициализации. Чтобы вызывать деструкторы, используется обратный порядок.

#include <iostream>
using namespace std;
class vect
{
int size;
int *array;
public:
vect(int size)
{
this->size = size;
array = new int[size];
for (int i = 0; i < size; i++)
array[i] = 0;
}
int& element(int i) { return array[i]; }
int getSize() { return size; }
};
class multi_v
{
public:
vect a;
vect b;
vect c;
multi_v(int size): a(size), b(size), c(size) { }
int getSize() { return a.getSize(); }
};
int main()
{
system(«chcp 1251»);
system(«cls»);
multi_v f(3);
for (int i = 0; i <= f.getSize(); i++)
{
f.a.element(i) = 10 + i;
f.b.element(i) = 20 + 5 * i;
f.c.element(i) = 120 + 5 * i;
}
for (int i = 0; i <= f.getSize(); i++)
{
cout << f.a.element(i) << «лет \t»;
cout << f.b.element(i) << «кг \t»;
cout << f.c.element(i) << «см» << endl;
}
cin.get();
return 0;
}

В конечном итоге каждому члену vect будет присвоен индивидуальный деструктор.

Нет комментариев

Оставить комментарий