§ 2. Классы

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

Для начальной инициализации класса используются конструкторы. Конструктор — специальный тип метода класса, который автоматически вызывается при создании объекта этого же класса. Конструкторы обычно используются для инициализации полей объекта класса (пример 2.3).

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

  • конструктор должен иметь то же имя, что и класс;
  • конструктор не имеет типа возврата.

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

В конструкторе может быть использован список инициализации полей класса. Список инициализации располагается после параметров конструктора. Он начинается с двоеточия (:), а затем значение для каждого поля указывается в круглых скобках. В теле конструктора не нужно выполнять операции присваивания, поэтому тело конструктора может быть пустым. Список инициализации членов класса не заканчивается точкой с запятой (пример 2.4).

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

ИмяКласса *this;

С его помощью метод класса определяет, с данными какого объекта ему предстоит работать. Указатель this можно использовать в конструкторах (пример 2.5).

Деструктор класса — еще один специальный метод — вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды: ~. Деструктор не имеет входных параметров. Деструктор всегда один. Для простых классов (тех, которые только инициализируют значения обычных свойств) деструктор не нужен, так как C++ автоматически выполнит очистку памяти самостоятельно. Деструкторы не вызываются пользователем явно. Однако их могут безопасно вызывать другие методы класса, т. к. объект не уничтожится до тех пор, пока не выполнится деструктор.

Пример 2.3. Добавление конструкторов в класс Student.

class Student

{

  private:

  /** поля для хранения фамилии

      и названия города **/

    string fam, gorod;

  /// поле - год рождения

    int god_r;

    vector <int> otm = vector<int>(3);

  public:

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

     Student ();

  /// конструктор

   Student (string f, string g, int r,

            int n0, int n1, int n2);

  /// метод для вычисления суммы отметок

    int summ();

  /// сеттеры для задания значения полей

    void set_fam(string f);

    void set_gorod(string g);

    void set_god_r(int r);

    void set_otm(vector <int> d);

  /** геттер для получения строки

     Фамилия Город Сумма баллов**/

    string get_fam_gor_summ();

};

Student::Student()

{

    gorod = "Минск";

    god_r = 2005;

}

 

Student::Student (string f, string g,

      int r, int n0, int n1, int n2)

{

    fam = f;

    gorod = g;

    god_r = r;

    otm[0] = n0;

    otm[1] = n1;

    otm[2] = n2;

}

Функция для ввода данных с использованием конструктора изменится следующим образом:

void vvod1 (vector <Student> &d)

{

  ifstream fin ("input.txt");

  int r;

  fin >> r;

  fin.ignore();

  d.resize(r);

  /** Считывание данных из файла и

      определение объектов с

      использованием конструктора **/

  for (int i = 0; i < r; i++){

    string t_str, g_str;

    fin >> t_str;

    fin >> g_str;

    int t_int;

    fin >> t_int;

    int b0, b1, b2;

    fin >> b0 >> b1 >> b2;

    d[i] = Student(t_str, g_str,

               t_int, b0, b1, b2);

  }

}

Пример 2.4. Использование списка инициализации при описании конструкторов в классе Student.

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

  Student () : gorod ("Минск"), god_(2005) {}

  /// конструктор

  Student (string f, string g, int r,

           int n0, int n1, int n2) :

              fam(f), gorod (g), 

              god_r (r), 

              otm ({n0, n1, n2}) {}

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

Пример 2.5. Использование указателя this в конструкторе класса Date.

Date::Date(int t_d, int t_m, int t_g)

{

    this -> d = t_d;

    this -> m = t_m;

    this -> g = t_g;

}