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

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

class Student{
    int age; //по умолчанию является private
public:
    void aging() {
        age++;
        cout << "Happy birthday! New age: " << age << endl;
    }
};

Непонятно как выставить начальное значение age.

Простейшее решение – до использования переменной вызывать некоторую функцию для ее инициализации, специальный публичный метод setAge().

class Student{
    int age; //по умолчанию является private
public:
    void setAge(int _age) {
        age = _age;
    }
    void aging() {
        age++;
        cout << "Happy birthday! New age: " << age << endl;
    }
};

Но это некрасивое и чреватое ошибками решение. Хорошо бы выставлять возраст студента только один раз, при создании и инициализации объекта. Это можно реализовать при помощи специального метода — конструктора.

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

Если объекты некоторого типа строятся нетривиально, то нужна еще одна дополнительная операция для удаления их после последнего использования. Функция удаления в С++ называется деструктором. Деструктор имеет то же имя, что и его класс, но перед ним стоит символ ~ (набирается на клавише с буквой Ё в английской раскладке).

class Student{
    int age;
public:
    Student(int _age) {
        age = _age;
        cout << "Student is enrolled. Welcome!" << endl;
    }
    ~Student() {
        cout << "Student is dismissed. Good by!" << endl;
    }
    void aging() {
        age++;
        cout << "Happy birthday! New age: " << age << endl;
    }
};

Заметьте, тип возвращаемого значения у конструктора отсутствует (слово void тоже писать не нужно). Конструктор, как и все другие методы, может иметь параметры, так как их значения необходимы ему при инициализации объекта.

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

Student s(17);
s.aging();

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

Что это значит для нас?

Student a; //Теперь это ошибка!
Student b(20);

Заметим важное преимущество, которое у нас появилось —теперь нельзя начать использовать неинициализированный объект студента, у которого не выставлен возраст.

Таким образом, отсутствие конструктора по умолчанию при наличии конструктора с параметрами — это гарантия инициализации объектов данного класса.

Деструктор не имеет ни возвращаемого значения, ни параметров, так как он вызывается автоматически.

Конструкторов может быть много (они могут быть перегружены по типам и количеству параметров), а деструктор всегда один.

Пример использования

При помощи конструктора и деструктора можно реализовать, например, автоматический подсчёт количества существующих на данный момент объектов:

int global_StudentCounter = 0;
class Student{
public:
    Student() {
        global_StudentCounter++;
    }
    ~Student() {
        global_StudentCounter--;
    }
};
int f() {
    cout << "in f()" << endl;
    Student a;
    cout << global_StudentCounter << endl;
}
int main() {
    cout << global_StudentCounter << endl;
    Student b;
    cout << global_StudentCounter << endl;
    {
        Student c;
        cout << global_StudentCounter << endl;
    }
    cout << global_StudentCounter << endl;
    f();
    cout << global_StudentCounter << endl;
}

Поскольку локальные переменные существуют только во время работы своей области видимости:функции и даже блока из фигурных скобок, например, тела цикла или просто, как в примере, блока из фигурных скобок — мы увидим в результате работы примера числа: 0, 1, 2, 1, 2, 1. Причём перед второй двойкой будет выведено "in f()".

Упражнения

  1. Объясните работу данного примера.
  2. Внесите данный пример в среду разработки и прогоните пример построчно в режиме отладки, осознав те строки, когда вызывается деструктор.
  3. Объясните в каждом случае для какого из объектов вызывается деструктор.

Вопрос

Что получится если сделать конструктор приватным?

Ответ

В этом случае конструктор без параметров также не будет создан автоматически. И если никаких публичных конструкторов нет, то экземпляр такого класса создать извне класса невозможно.

Тем не менее, такие классы на практике существуют, и их экземпляры создаются из их же методов или из дружественных функций.