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

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?

Да, может. Такой конструктор называется приватным конструктором (private constructor).

12. В каких случаях могут создаваться приватные конструкторы?

При объявлении обычного объекта класса, конструкторы, которые размещены в разделе private (приватные конструкторы), есть недоступными.

Чтобы использовать приватные конструкторы, нужно выполнение одного из трех условий:

  • конструктор вызывается статическим членом класса;
  • конструктор вызывается дружественным классом;
  • в классе объявлена функция-член, которая вызовет данный конструктор для создания нового объекта.

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

В этом случае будет ошибка компиляции.

Например. Пусть задан класс CMyDate. В классе определен явно заданный конструктор по умолчанию (без параметров).

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

Попытка создать объект класса приведет к ошибке компиляции

CMyDate MD; // ошибка компиляции

То же самое будет, если попробовать создать статический объект

static CMyDate MDS; // ошибка компиляции также для статического объекта

14. Может ли в классе быть объявлено два конструктора, которые принимают одинаковое количество параметров?

Да, может. Однако с условием, что типы параметров будут отличаться. Для класса должно выполняться правило:

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

Этот вопрос тесно связан с темой перегрузки функций.

 

15. Какие конструкторы называются параметризованными?

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

 

16. Какие существуют способы инициализации членов объекта с помощью конструктора, который получает один параметр? Пример

Для конструктора, получающего один параметр существует два способа инициализации:

  • инициализация по образцу вызова функции;
  • инициализация по образцу оператора присваивания.

Пример. Пусть задан класс, в котором определяется одна переменная n типа int. Класс имеет два конструктора. Первый – конструктор без параметров, обнуляющий значение 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


Связанные темы