Конструкторы и деструкторы

Язык C++ / Конструкторы и деструкторы

 

Конструкторы

Конструктор — функция, предназначенная для инициализации объектов класса.Рассмотрим класс date:

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


Нигде не утверждается, что объект должен быть инициализирован, и программист может забыть инициализировать его или сделать это дважды.
ООП дает возможность программисту описать функцию, явно предназначенную для инициализации объектов. Поскольку такая функция конструирует значения данного типа, она называется конструктором. Конструктор всегда имеет то же имя, что и сам класс и никогда не имеет возвращаемого значения. Когда класс имеет конструктор, все объекты этого класса будут проинициализированы.
 
 
 
 
 
class date {
  int day, month, year;
public:
  date(intintint); // конструктор
};


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


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


Конструкторы подчиняются тем же правилам относительно типов параметров, что и перегруженные функции. Если конструкторы существенно различаются по типам своих параметров, то компилятор при каждом использовании может выбрать правильный:
 
 
 
date july4("Февраль 27, 2014");
date guy(27, 2, 2014);
date now; // инициализируется по умолчанию


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

Конструктор по умолчанию

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

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


При создании объекта вызывается конструктор, за исключением случая, когда объект создается как копия другого объекта этого же класса, например:
 
date date2 = date1;


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

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

Во всех этих случаях транслятор не вызывает конструктора для вновь создаваемого объекта:

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

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

  • date1 в приведенном примере;
  • фактического параметра;
  • объекта-результата в операторе 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 деструктор будет иметь имя ~X(). Многие классы используют динамическую память, которая выделяется конструктором, а освобождается деструктором.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 объекта класса vect: a, b, c.

Конструкторы членов класса всегда выполняются до конструктора класса, в котором эти члены описаны. Порядок выполнения конструкторов для членов класса определяется порядком объявления членов класса. Если конструктору члена класса требуются аргументы, этот член с нужными аргументами указывается в списке инициализации. Деструкторы вызываются в обратном порядке.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#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;
}

При выполнении программы перед выходом из блока main для каждого члена vect будет вызываться индивидуальный деструктор. Результат работы программы
Поля, имеющие тип класса


Назад: Язык C++

Комментариев к записи: 2

  • Здравствуйте, у меня такой вопрос. В коде я не нашел сам деструктор. Он создается и запускается сам после выхода из блока main ?

    • Елена Вставская
      Если явно в коде не присутствует, то да, запускается при выходе из main()

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *