C++. Конструктор класу. Особливості використання конструкторів у класах. Конструктор за замовчуванням. Параметризовані конструктори. Приклади класів, що містять конструктори

C++. Класи. Частина 2. Конструктор класу. Особливості використання конструкторів у класах. Конструктор за замовчуванням. Параметризовані конструктори. Приклади класів, що містять конструктори

У даній темі розглядається поняття конструктора на прикладі unmanaged (native) класів. Матеріали даної теми також стосуються і конструкторів managed-класів.


Зміст



1. Що називається конструктором класу? Яке призначення конструктора?

Клас може містити спеціальні функції: конструктори і деструктори.

Конструктор класу – це спеціальний метод (функція) класу. Конструктор викликається при створенні об’єкту класу. Як правило, конструктор використовується для:

  • виділення пам’яті для об’єкту класу;
  • початкової ініціалізації внутрішніх даних класу.

Конструктор призначений для формування екземпляру об’єкту класу.

Ім’я конструктора класу співпадає з іменем класу.

2. В який момент роботи програми здійснюється виклик конструктора класу?

Виклик конструктора здійснюється при створенні об’єкту класу. Конструктор класу викликається компілятором.

3. Чи може конструктор мати параметри? Приклади конструкторів з різною кількістю параметрів

Конструктор може мати будь-яку кількість параметрів. Також конструктор може бути без параметрів (конструктор за замовчуванням).

Приклад. Оголошується клас CMyDate, що визначає дату (число, місяць, рік). У класі оголошено два конструктори. Один конструктор без параметрів, інший конструктор, що отримує три параметри, що встановлюють нову дату.

Оголошення класу та його методів має вигляд

// клас, що визначає дату
class CMyDate
{
    int day;
    int month;
    int year;

    public:
    // конструктори класу
    CMyDate(); // конструктор без параметрів
    CMyDate(int d, int m, int y); // конструктор з трьома параметрами

    // методи класу
    void SetDate(int d, int m, int y); // встановити нову дату
    int GetDay(void); // повертає номер дня
    int GetMonth(void); // повертає номер місяця
    int GetYear(void); // повертає рік
};

// реалізація конструкторів та методів класу
// конструктор без параметрів (конструктор за замовчуванням)
CMyDate::CMyDate()
{
    // встановити дату 01.01.2001
    day = 1;
    month = 1;
    year = 2001;
}

// конструктор з трьома параметрами
CMyDate::CMyDate(int d, int m, int y)
{
    day = d;
    month = m;
    year = y;
}

// Встановити нову дату
void CMyDate::SetDate(int d, int m, int y)
{
    day = d;
    month = m;
    year = y;
}

// зчитати номер дня
int CMyDate::GetDay(void)
{
    return day;
}

// зчитати номер місяця
int CMyDate::GetMonth(void)
{
    return month;
}

// зчитати рік
int CMyDate::GetYear(void)
{
    return year;
}

Демонстрація виклику конструкторів при оголошенні об’єктів класу

CMyDate MD1; // викликається конструктор без параметрів
CMyDate MD2(4, 5, 2008); // викликається конструктор з трьома параметрами

int t;
t = MD1.GetDay(); // t = 1
t = MD1.GetYear(); // t = 2001

t = MD2.GetMonth(); // t = 5
t = MD2.GetYear(); // t = 2008

4. Чи обов’язково в класі описувати конструктор?

Не обов’язково. При створенні об’єкту класу, що не містить жодного конструктора, буде викликатись так званий конструктор за замовчуванням (default constructor), який виділить пам’ять для об’єкту класу. Але, в класі можна оголосити власний конструктор за замовчуванням. Такий конструктор називається: явно заданий конструктор за замовчуванням.

5. Що таке конструктор за замовчуванням (default constructor)? Приклади

Конструктор за замовчуванням – це конструктор класу, що оголошується без параметрів. Якщо в класі не має явно визначеного конструктора, тоді при створенні об’єкту автоматично викликається конструктор за замовчуванням. Конструктор за замовчуванням просто виділяє пам’ять для об’єкту класу, коли він оголошується.

Приклад 1. Нехай задано клас CMyPoint, що визначає точку на координатній площині. У класі не реалізовано жодного конструктора.

// клас, що визначає точку на координатній площині
class CMyPoint
{
    int x;
    int y;

    public:
    // методи класу
    void SetPoint(int nx, int ny)
    {
        x = nx;
        y = ny;
    }

    int GetX(void) { return x; }
    int GetY(void) { return y; }
};

Однак, при створенні об’єкту класу компілятор автоматично викликає конструктор за замовчуванням.

CMyPoint MP; // автоматично викликається конструктор за замовчуванням
MP.SetXY(4, -10); // виклик методів класу

int t;
t = MP.GetY(); // t = -10

Конструктор за замовчуванням автоматично викликається тільки тоді, коли в класі не оголошено жодного конструктора. Як тільки в класі оголосити будь-який інший конструктор з параметрами, то при оголошенні

CMyPoint MP;

компілятор видасть помилку.

Приклад 2. Модифікація класу CMyPoint. У класі явно задано конструктор за замовчуванням.

// клас, що визначає точку на координатній площині
class CMyPoint
{
    int x;
    int y;

    public:
    // явно заданий конструктор за замовчуванням
    CMyPoint()
    {
        x = y = 0;
    }

    // методи класу
    void SetPoint(int nx, int ny)
    {
        x = nx;
        y = ny;
    }

    int GetX(void) { return x; }
    int GetY(void) { return y; }
};

Демонстрація виклику явно заданого конструктора за замовчуванням

CMyPoint MP; // викликається явно заданий конструктор за замовчуванням

int t;
t = MP.GetX(); // t = 0

6. Скільки конструкторів за замовчуванням може мати клас?

Кожен клас може мати тільки один конструктор за замовчуванням. Це зв’язано з тим, що у класі не може бути двох методів (функцій) з однаковою сигнатурою.

7. Чи може конструктор повертати значення?

Конструктор не може повертати значення (навіть значення void). Якщо в конструкторі написати повернення значення з допомогою оператора return, то компілятор видасть помилку.

8. Приклад оголошення та використання класу, що містить декілька конструкторів. Реалізація типу string в класі

Наприклад, потрібно оголосити клас, що містить інформацію про ім’я працівника та його вік.

Для представлення внутрішніх членів даних у класі використовується тип string. Щоб використовувати тип string у програмах на Visual C++, потрібно на початку модуля, що описує клас, підключити бібліотеку <string> та простір імен std

#include <string>
using namespace std;

Оголошення класу

// Клас, що визначає загальні дані про клієнта
class CName
{
    string name; // Прізвище
    string surname; // ім'я
    string patronymic; // по-батькові
    int age; // вік

    public:
    CName(void); // конструктор без параметрів
    CName(string n_name, string n_sname); // конструктор з двома параметрами
    CName(string n_name, string n_sname, string n_patr); // конструктор з трьома параметрами
    CName(string n_name, string n_sname, string n_patr, int n_age); // 4 параметри

    // внутрішні методи класу - реалізовані в оголошенні класу
    string GetName(void) { return name; }
    string GetSurname(void) { return surname; }
    string GetPatr(void) { return patronymic; }
    int GetAge(void) { return age; }

    ~CName(void); // деструктор
};

Реалізація конструкторів та деструктора класу

// реалізація конструкторів та деструктора класу
// конструктор без параметрів
CName::CName(void)
{
    name = "";
    surname = "";
    patronymic = "";
    age = 0;
}

// конструктор з двома параметрами
CName::CName(string n_name, string n_sname)
{
    name = n_name;
    surname = n_sname;
    patronymic = "";
    age = 0;
}

// конструктор з трьома параметрами
CName::CName(string n_name, string n_sname, string n_patr)
{
    name = n_name;
    surname = n_sname;
    patronymic = n_patr;
    age = 0;
}

// конструктор з 4 параметрами
CName::CName(string n_name, string n_sname, string n_patr, int n_age) // 4 параметри
{
    name = n_name;
    surname = n_sname;
    patronymic = n_patr;
    age = n_age;
}

CName::~CName(void)
{

}

9. Як працює конструктор класу у випадку, коли в класі оголошено об’єкт іншого класу (підоб’єкт)? Приклад

У цьому випадку:

  • першим викликається конструктори (конструктори) класу, що є підоб’єктом включаючого класу;
  • наступним викликається конструктор включаючого класу.

Приклад. Нехай задано 2 класи: CMyPoint, CMyLine. У класі CMyLine є два підоб’єкти класу CMyPoint. При створенні об’єкту класу CMyLine, спочатку викликаються 2 конструктори класу CMyPoint для двох підоб’єктів, а потім викликається конструктор класу CMyLine.

// клас CMyPoint
class CMyPoint
{
    int x, y;

    public:
    CMyPoint(void); // конструктор класу
};

// конструктор класу CMyPoint
CMyPoint::CMyPoint(void)
{
    // ...
}

// клас CMyLine
class CMyLine
{
    CMyPoint p1;
    CMyPoint p2;

    public:
    CMyLine(void);
};

// конструктор класу CMyLine
CMyLine::CMyLine(void)
{
    // ...
}

Оголошення об’єкту класу CMyLine

CMyLine ML; // викликаються: 1 - два конструктори CMyPoint(), 2 - конструктор CMyLine()

Після такого оголошення конструктори викликаються у такій послідовності:

  • CMyPoint::CMyPoint() для об’єкта p1 класу CMyLine;
  • CMyPoint::CMyPoint() для об’єкта p2 класу CMyLine;
  • CMyLine::CMyLine() для об’єкта ML.

10. Як працює конструктор класу у випадку, коли створюється об’єкт класу, який є похідним (успадкованим) від іншого класу?

Якщо є два класи, один з яких базовий а інший – породжений (успадкований) від базового, то в цьому випадку послідовність викликів наступна:

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

11. Чи може конструктор оголошуватись у розділі private?

Так, може. Такий конструктор називається приватним конструктором.

12. У яких випадках можуть створюватись приватні конструктори?

При оголошенні звичайного об’єкту класу, конструктори, які розміщені в розділі private (приватні конструктори), є недоступними.

Щоб використовувати приватні конструктори, потрібно виконання однієї з трьох умов:

  • конструктор викликається статичним членом класу;
  • конструктор викликається дружнім класом;
  • у класі оголошена функція-член, яка викликає даний конструктор для створення нового об’єкту.

Більш детально робота статичних членів класу та дружніх класів описується в інших темах.

13. Як буде працювати програма, якщо спробувати створити об’єкт класу, в якому оголошено приватний конструктор за замовчуванням?

У цьому випадку буде помилка компіляції.

Наприклад. Нехай задано клас CMyDate. У класі оголошено явно заданий конструктор за замовчуванням (без параметрів).

class CMyDate
{
    private:
    // явно заданий конструктор за замовчуванням
    CMyDate()
    {
        // тіло конструктора
        // ...
    }
}

Спроба створити об’єкт класу приведе до помилки компіляції

CMyDate MD; // помилка компіляції

Те саме буде, якщо спробувати створити статичний об’єкт

static CMyDate MDS; // помилка компіляції також для статичного об’єкту

14. Чи може в класі бути оголошено два конструктори, що приймають однакову кількість параметрів?

Так можуть. Однак з умовою, що типи параметрів будуть відрізнятись. Для класу повинно виконуватись правило:

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

Це питання тісно пов’язане з темою перевантаження функцій.

15. Які конструктори називаються параметризованими?

Параметризований конструктор – це конструктор класу, що має параметри.

16. Які існують способи ініціалізації членів об’єкту з допомогою конструктора, що отримує один параметр? Приклад

Існує два способи:

  • ініціалізація за зразком виклику функції;
  • ініціалізація за зразком оператора присвоєння.

Приклад. Нехай задано клас, в якому визначається одна змінна n типу int. Клас має 2 конструктори. Перший – конструктор без параметрів, який занулює значення n. Другий – конструктор з одним параметром, який встановлює нове значення n.

Загальний вигляд оголошення класу

class CMyInt
{
    private:
    int n; // кількість елементів масиву

    public:
    CMyInt(void) { }; // конструктор за замовчуванням
    ~CMyInt(void); // деструктор
    CMyInt(int nn) { n = nn; } // конструктор з одним параметром

    // методи класу
    void SetN(int nn) { n = nn; }
    int GetN(void) { return n; }
};

Оголосити об’єкт класу CMyInt з використанням конструктора з 1 параметром можна двома способами

// Демонстрація оголошення об'єкту класу,
// якщо в класі реалізовано конструктор з 1 параметром
CMyInt MI1(10); // виклик конструктора з 1 параметром
CMyInt MI2 = 20; // те саме, інший спосіб

int t;
t = MI1.GetN(); // t = 10
t = MI2.GetN(); // t = 20


Зв’язані теми