24. C++ Конструкторы и деструктор класса

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

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

Примечание: в дальнейшем в статье словом «специфический» обозначено нестандартное выделение/выделение не по умолчанию / работа с динамической памятью и тд

  • Как было сказано в более ранних статьях, классы – своего рода шаблоны, по которым собираются объекты/переменные класса, а у всех переменных есть зона видимости, т.е. зона где переменная «создается->существует->удаляется» для простых типов данных, хранящихся на стеке это относительно просто, они удаляются автоматически (об этом заботится компилятор), для динамической памяти в языке C++ выделение и уничтожение памяти лежит на программисте.
    Значит процесс создания класса и удаление должны быть «специфическими».
  • Также стоит сказать, что создание неинициализированного класса, как и создание неинициализированной переменной может приводить к ошибкам (например переменная string, которая пустая, или int, который не инициализирован 0).

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

Внешне они выглядят так:

class myClass{
myClass(){}//конструктор
~myClass(){}//деструктор

};

Расмотрим реализацию конструктора на примере:

Возьмем наш класс Person, где поле age будет расположено в динамической памяти.

class Person
{
public:
  Person(string Name, unsigned int age)
  {
      this->Name=Name;
      this->age= new unsigned int (age); //создание переменной в динамической памяти
  }

  ~Person()
  {
      delete age; //удаление переменной в динамической памяти
  }

 void getInfo()
 {
   cout<<"Name: "<< this->Name <<" age "<< *(this->age) <<endl; //выводим данные на экран
 }

private:
  string Name;
  unsigned int * age; //указатель на переменную в динамической памяти
};

В функции main:

//Создадим объект класса Person и проинициализируем его поля.
Person c_Person1("Vasya",30);
c_Person1.getInfo(); //Выведет в консоль Name Vasya age 30

Что же мы сделали:

1-вызвали конструктор (считай что функцию инициализации) Person(string Name, unsigned int age), в которую передали параметры, и внутри нее создали переменную в динамической памяти.
p.s. переменную создавали внутри просто для простоты, можно передавать указатель и через аргументы конструктора.

2-После мы можем работать с классом например вызвать метод getInfo().

3-Вот тут кроется интересный момент, переменные string Name; и указатель unsigned int age;  расположены на стеке, поэтому они удаляются автоматически, а данные, на которые ссылается указатель останутся.

При выходе класса из зоны видимости (например функции/цикла и тд) очистится память в стеке, содержащая указатель на age, и при отсутствии деструктора произойдет утечка, но мы написали деструктор ~Person() в котором освободили динамическую память.

Теперь при уничтожении объекта класса будет вызван деструктор и память освободится.

Важный момент: конструктор, как и любой метод или функцию можно перегрузить – т.е. написать несколько реализаций, деструктор может быть ТОЛЬКО ОДИН

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

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