Что такое конструктор и для чего он нужен, Какие типы конструктора существуют
В объектно-ориентированном программировании конструктор класса (от англ. constructor, иногда сокращают ctor) — специальный блок инструкций, вызываемый при создании объекта, причём или при его объявлении (располагаясь в стеке или в статической памяти, что допустимо в C++, но не в Java и некоторых других объектно-ориентированных языках) или динамически располагаясь в куче при использовании ключевого слова new.
Конструкторы часто выделяются наличием одинакового имени с именем класса, в котором объявляется. Их задача — инициализировать члены объекта и определить инвариант класса, сообщив в случае некорректности инварианта. Корректно написанный конструктор оставит объект в ‘правильном’ статусе. Неизменяемые объекты тоже должны быть проинициализированы конструктором.
//вызов конструктора с параметрами для создания объекта b:
//вызов конструктора копирования для создания объекта c:
//вызов конструктора с параметрами для безымянного объекта
//и вызов конструктора копирования для определения объекта d:
person d = person(«Gurgen»,1942);
//вызов конструктора без параметров для создания безымянного
//объекта, размещаемому по адресу, хранящемуся в указателе pp1:
person* pp1 = new person;
//вызов конструктора с параметрами для создания безымянного
//объекта, размещаемого по адресу, хранящемуся в указателе pp2:
person* pp2 = new person(«Ivan»,1978);
//вызов конструктора копирования для возврата значения функцией
person e = set_info();
//вызов конструктора копирования для создания объекта-параметра //функции:
print(a); print(b); print(c); print(d);
print(*pp1); print(*pp2); print(e);
Отличие конструктора копирования от операции присваивания в С++
Копирующий конструктор предназначен для создания нового объекта по подобию уже существующего, но это не то же самое, что и копирующий оператор присваивания. Тот должен правильно работать с уже созданным объектом.
Деструктор, назначение деструктора.
Если создание объекта подразумевает выделение каких-либо ресурсов, то таким классам требуется функция, которая освободит ресурсы, выделяемые конструктором. Такая функция называется деструктором, она будет автоматически вызвана при уничтожении объекта.
Деструктор не имеет параметров и возвращаемого значения. Вызов деструктора выполняется неявно, при уничтожении объекта класса.
Если в классе деструктор не определен явно, то компилятор генерирует деструктор по умолчанию, который просто освобождает память, занятую данными объекта. В тех случаях, когда требуется выполнить освобождение ресурсов, выделенных конструктором, необходимо определить деструктор явно.
Деструктор вызывается автоматически, когда объект удаляется из памяти:
для локальных объектов это происходит при выходе из блока, в котором они объявлены;
для глобальных — как часть процедуры выхода из main;
для объектов, заданных через указатели, деструктор вызывается неявно при использовании операции delete.
Имя деструктора начинается с тильды (
), непосредственно за которой следует имя класса.
не имеет аргументов и возвращаемого значения;
не может быть объявлен как const или static (см. далее);
может быть виртуальным (см. далее).
Если деструктор явным образом не определен, компилятор автоматически создает пустой деструктор.
Описывать в классе деструктор явным образом требуется в случае, когда объект содержит указатели на память, выделяемую динамически — иначе при уничтожении объекта память, на которую ссылались его поля-указатели, не будет помечена как свободная. Указатель на деструктор определить нельзя.
Деструктор для рассматриваемого примера будет выглядеть так:
//реализация деструктора для экземпляра класса
Без необходимости явно вызывать деструктор объекта не рекомендуется.
Наследование классов в С++
Наследование – это такое отношение между классами, когда один класс частично или полностью повторяет структуру и поведение другого класса (одиночное наследование) или других (множественное наследование) классов. Наследование устанавливает между классами иерархию «общее-частное».
Связи наследования также называют обобщениями (generalization) и изображают в виде больших белых стрелок от класса-потомка к классу-предку
Рассмотрим учет сотрудников организации. Каждый сотрудник – это, прежде всего, человек. Студент, работник, руководитель – частные случаи объекта «человек», определяющего общие характеристики для всех своих разновидностей. Организация этих понятий в иерархию позволяет избежать повторения кода и обращаться с объектами производных классов как с объектами базового.
Возьмем за основу иерархии класс person, немного изменив его структуру ради соответствия концепции наследования. Поскольку для всех объектов кадровой структуры требуется знать имя, фамилию, а также год рождения для определения возраста, объявим данные атрибуты как protected, заменив заодно тип представления имени и отчества на более удобный в работе тип string.
C++. Классы. Часть 2. Конструктор класса. Особенности использования конструкторов в классах. Конструктор по умолчанию. Параметризированные конструкторы. Примеры классов, содержащих конструкторы
В данной теме рассматривается понятие конструктора на примере unmanaged ( native ) классов. Материалы данной темы также касаются и конструкторов managed- классов.
Содержание
- 1. Что называется конструктором класса? Какое назначение конструктора?
- 2. В какой момент работы программы осуществляется вызов конструктора класса?
- 3. Может ли конструктор иметь параметры? Примеры конструкторов с разным количеством параметров
- 4. Обязательно ли в классе описывать конструктор?
- 5. Что такое конструктор по умолчанию (default constructor)? Примеры
- 6. Сколько конструкторов по умолчанию может иметь класс?
- 7. Может ли конструктор возвращать значение?
- 8. Пример объявления и использования класса, который содержит несколько конструкторов. Реализация типа string в классе
- 9. Как работает конструктор класса в случае, когда в классе объявлен объект другого класса (подобъект)? Пример
- 10. Как работает конструктор класса в случае, когда создается объект класса, который есть производным (унаследованным) от другого класса?
- 11. Может ли конструктор объявляться в разделе private ?
- 12. В каких случаях могут создаваться приватные конструкторы?
- 13. Как будет работать программа, если попробовать создать объект класса, в котором объявлен приватный конструктор по умолчанию?
- 14. Может ли в классе быть объявлено два конструктора, которые принимают одинаковое количество параметров?
- 15. Какие конструкторы называются параметризованными?
- 16. Какие существуют способы инициализации членов объекта с помощью конструктора, который получает один параметр? Пример
Поиск на других ресурсах:
1. Что называется конструктором класса? Какое назначение конструктора?
Класс может содержать специальные функции: конструкторы и деструкторы .
Конструктор класса – это специальный метод (функция) класса. Конструктор вызывается при создании объекта класса. Как правило, конструктор используется для:
- выделения памяти под объект класса;
- начальной инициализации внутренних данных класса.
Конструктор предназначен для формирования экземпляра объекта класса. Имя конструктора класса совпадает с именем класса.
2. В какой момент работы программы осуществляется вызов конструктора класса?
Вызов конструктора осуществляется при создании объекта класса. Конструктор класса вызывается компилятором.
3. Может ли конструктор иметь параметры? Примеры конструкторов с разным количеством параметров
Конструктор может иметь любое количество параметров. Также конструктор может быть без параметров (конструктор по умолчанию).
Пример. Объявляется класс CMyDate , определяющий дату (число, месяц, год). В классе объявлены два конструктора. Один конструктор без параметров, другой конструктор, получающий три параметра, которые устанавливают новую дату.
Объявление класса и его методов имеет вид
Демонстрация вызова конструкторов при объявлении объектов класса
4. Обязательно ли в классе описывать конструктор?
Не обязательно. При создании объекта класса, который не содержит ни одного конструктора, будет вызываться неявно заданный конструктор по умолчанию (default constructor), выделяющий память для объекта класса. Однако, в классе можно объявить собственный конструктор по умолчанию. Такой конструктор называется: явно заданный конструктор по умолчанию.
5. Что такое конструктор по умолчанию ( default constructor )? Примеры
Конструктор по умолчанию – это конструктор класса, который объявляется без параметров. Если класс не содержит явным образом определенный конструктор, тогда при создании объекта автоматически вызывается конструктор по умолчанию. Конструктор по умолчанию просто выделяет память для объекта класса, если он объявляется.
Пример 1. Пусть задан класс CMyPoint , определяющий точку на координатной плоскости. В классе не реализовано ни одного конструктора.
Однако, при создании объекта класса компилятор автоматически вызовет конструктор по умолчанию.
Конструктор по умолчанию автоматически вызовется только тогда, если в классе не объявлено ни одного конструктора. Как только в классе объявить любой другой конструктор с параметрами, то при объявлении
компилятор выдаст ошибку.
Пример 2. Модификация класса CMyPoint . В классе присутствует явно заданный конструктор по умолчанию.
Демонстрация вызова явным образом заданного конструктора по умолчанию
6. Сколько конструкторов по умолчанию может иметь класс?
Каждый класс может иметь только один конструктор по умолчанию. Это связано с тем, что в классе не может быть двух методов (функций) с одинаковой сигнатурой.
7. Может ли конструктор возвращать значение?
Конструктор не может возвращать значения (даже значение void ). Если в конструкторе написать возвращение значения с помощью оператора return , то компилятор выдаст ошибку.
8. Пример объявления и использования класса, который содержит несколько конструкторов. Реализация типа string в классе
Например, нужно объявить класс, который содержит информацию об имени работника и его возраст.
Для представления внутренних членов данных в классе используется тип string . Чтобы использовать тип string в программах на Visual C++, нужно в начале модуля, который описывает класс, подключить библиотеку < string > и пространство имен std
Реализация конструкторов и деструктора класса
9. Как работает конструктор класса в случае, когда в классе объявлен объект другого класса (подобъект)? Пример
- первым вызывается конструктор (конструкторы) класса, который есть подобъектом включающего класса;
- следующим вызывается конструктор включающего класса.
Пример. Пусть заданы 2 класса: CMyPoint , CMyLine . В классе CMyLine есть два подобъекта класса CMyPoint . При создании объекта класса CMyLine , сначала будут вызваны 2 конструктора класса CMyPoint для двух подобъектов, а потом вызовется конструктор класса CMyLine .
Объявление объекта класса CMyLine
После такого объявления конструкторы вызовутся в следующей последовательности:
- CMyPoint::CMyPoint() для объекта p1 класса CMyLine() ;
- CMyPoint::CMyPoint() для объекта p2 класса CMyLine() ;
- CMyLine::CMyLine() для объекта ML .
10. Как работает конструктор класса в случае, когда создается объект класса, который есть производным (унаследованным) от другого класса?
Если есть два класса, один из которых базовый а другой — унаследованный от базового, то в этом случае последовательность вызовов следующая:
- сначала вызовется конструктор базового класса;
- следующим вызовется конструктор унаследованного класса.
11. Может ли конструктор объявляться в разделе private ?
Да, может. Такой конструктор называется приватным конструктором (private constructor).
12. В каких случаях могут создаваться приватные конструкторы?
При объявлении обычного объекта класса, конструкторы, которые размещены в разделе private (приватные конструкторы), есть недоступными.
Доступ к созданию объектов с помощью приватных конструкторов имеют:
- методы, объявленные в классе (методы-члены класса). Сюда относятся также и статические методы, объявленные с ключевым словом static ;
- методы дружественных классов (дружественные методы).
13. Как будет работать программа, если попробовать создать объект класса, в котором объявлен приватный конструктор по умолчанию?
В этом случае будет ошибка компиляции.
Например. Пусть задан класс CMyDate . В классе определен явно заданный конструктор по умолчанию (без параметров).
Попытка создать объект класса приведет к ошибке компиляции
То же самое будет, если попробовать создать статический объект
14. Может ли в классе быть объявлено два конструктора, которые принимают одинаковое количество параметров?
Да, может. Однако с условием, что типы параметров будут отличаться. Для класса должно выполняться правило:
- в классе не может быть двух методов (функций) с одинаковой (совпадающей) сигнатурой.
Этот вопрос тесно связан с темой перегрузки функций.
15. Какие конструкторы называются параметризованными?
Параметризованный конструктор – это конструктор класса, который имеет параметры.
16. Какие существуют способы инициализации членов объекта с помощью конструктора, который получает один параметр? Пример
Для конструктора, получающего один параметр существует два способа инициализации:
- инициализация по образцу вызова функции;
- инициализация по образцу оператора присваивания.
Пример. Пусть задан класс, в котором определяется одна переменная n типа int . Класс имеет два конструктора. Первый – конструктор без параметров, обнуляющий значение n . Второй – конструктор с одним параметром, устанавливающий новое значение n .
Общий вид объявления класса
Объявить объект класса CMyInt с использованием конструктора с 1 параметром можно двумя способами
Конструктор и деструктор классов в C++
Начнем с того, что когда мы создаем элементы (переменные) класса, мы не можем присвоить им значения в самом определении класса. Компилятор выдаст ошибку. Поэтому нам необходимо создавать отдельный метод (так называемую set-функцию) класса, с помощью которого и будет происходить инициализация элементов. При этом, если необходимо создать, к примеру, 20 объектов класса, то чтобы инициализировать элементы потребуется 20 раз вызвать set-функции.
Тут нам как раз сможет помочь конструктор класса. Кстати, конструктор (от слова construct — создавать) – это специальный метод класса, который предназначен для инициализации элементов класса некоторыми начальными значениями.
В отличии от конструктора, деструктор (от слова destruct — разрушать) — специальный метод класса, который служит для уничтожения элементов класса. Чаще всего его используют тогда, когда в конструкторе,при создании объекта класса, динамически был выделен участок памяти и необходимо эту память очистить, если эти значения уже не нужны для дальнейшей работы программы.
- конструктор и деструктор, мы всегда объявляем в разделе public ;
- при объявлении конструктора, тип данных возвращаемого значения не указывается, в том числе — void . ;
- у деструктора также нет типа данных для возвращаемого значения, к тому же деструктору нельзя передавать никаких параметров;
- имя класса и конструктора должно быть идентично;
- имя деструктора идентично имени конструктора, но с приставкой
Сразу хочу привести пример, который доступно покажет, как работает конструктор:
Результат работы программы:
Как видно из результата работы программы, конструктор срабатывает сразу, при создании объектов класса, поэтому, явно вызывать конструктор не нужно, он сам «приходит» 🙂
Хочется еще добавить, что, как и обычным функциям, мы можем передавать конструктору параметры. Через параметры, конструктору можно передавать любые данные, которые будут необходимы при инициализации объектов класса.
Рассмотрим еще один пример, это все та же программа, только в код внесены некоторые изменения. Тут же покажем принцип работы деструктора:
Смотрим результат работы программы :
Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные. Мы его не вызывали – он сработал сам. Как видно, он сработал 2 раза, так как и конструктор. Уже от себя добавлю, что, в первую очередь, он удалил второй созданный объект (где a = 200, b = 200), а затем первый (где a = 100, b = 100). «Последним пришёл — первым вышел».
Для чего используются конструкторы
Конструкторы представляют специальную функцию, которая имеет то же имя, что и класс, которая не возвращает никакого значения и которая позволяют инициалилизировать объект класса во время го создания и таким образом гарантировать, что поля класса будут иметь определенные значения. При каждом создании нового объекта класса вызывается конструктор класса.
В прошлой теме был разработан следующий класс:
Здесь при создании объекта класса Person, который называется person
вызывается конструктор по умолчанию . Если мы не определяем в классе явным образом конструктор, как в случае выше, то компилятор автоматически компилирует конструктор по умолчанию. Подобный конструктор не принимает никаких параметров и по сути ничего неи делает.
Теперь определим свой конструктор. Например, в примере выше мы устанавливаем значения для полей класса Person. Но, допустим, мы хотим, чтобы при создании объекта эти поля уже имели некоторые значения по умолчанию. Для этой цели определим конструктор:
Теперь в классе Person определен конструктор:
По сути конструктор представляет функцию, которая может принимать параметры и которая должна называться по имени класса. В данном случае конструктор принимает два параметра и передает их значения полям name и age, а затем выводит сообщение о создании объекта.
Если мы определяем свой конструктор, то компилятор больше не создает конструктор по умолчанию. И при создании объекта нам надо обязательно вызвать определенный нами конструктор.
Вызов конструктора получает значения для параметров и возвращает объект класса:
После этого вызова у объекта person для поля name будет определено значение «Tom», а для поля age — значение 38. Вполедствии мы также сможем обращаться к этим полям и переустанавливать их значения.
В качестве альтернативы для создания объекта можно использовать инициализатор в фигурных скобках:
Тажке можно присвоить объекту результат вызова конструктора:
По сути она будет эквивалетна предыдущей.
Консольный вывод определенной выше программы:
Конструкторы облегчают нам создание нескольких объектов, которые должны иметь разные значения:
Здесь создаем три разных объекта класса Person (условно трех разных людей), и соответственно в данном случае консольный вывод будет следующим:
Определение нескольких конструкторов
Подобным образом мы можем определить несколько конструкторов и затем их использовать:
В классе Person определено три конструктора, и в функции все эти конструкторы используются для создания объектов:
Хотя пример выше прекрасно работает, однако мы можем заметить, что все три конструктора выполняют фактически одни и те же действия — устанавливают значения переменных name и age. И в C++ можем сократить их определения, вызова из одного конструктора другой и тем самым уменьшить объем кода:
Запись Person(string p_name): Person(p_name, 18) представляет вызов конструктора, которому передается значение параметра p_name и число 18. То есть второй конструктор делегирует действия по инициализации переменных первому конструктору. При этом второй конструктор может дополнительно определять какие-то свои действия.
Таким образом, следующее создание объекта
будет использовать третий конструктор, который в свою очередь вызывает второй конструктор, а тот обращается к первому конструктору.
Данная техника еще называется делегированием конструктора , поскольку мы делегируем инициализацию другому конструктору.
Параметры по умолчанию
Как и другие функции, конструкторы могут иметь параметры по умолчанию:
Инициализация констант и списки инициализации
В теле конструктора мы можем передать значения переменным класса. Однако константы требуют особого отношения. Например, вначале определим следующий класс:
Этот класс не будет компилироваться из-за отсутствия инициализации константы name. Хотя ее значение устанавливается в конструкторе, но к моменту, когда инструкции из тела конструктора начнут выполняться, константы уже должны быть инициализированы. И для этого необходимо использовать списки инициализации :
Списки инициализации представляют перечисления инициализаторов для каждой из переменных и констант через двоеточие после списка параметров конструктора:
Здесь выражение name
Списки инициализации пободным образом можно использовать и для присвоения значений переменным:
При использовании списков инициализации важно учитывать, что передача значений должна идти в том порядке, в котором константы и переменные определены в классе. То есть в данном случае в классе сначала определена константа name, а потом переменная age. Соответственно в таком же порядке идет передача им значений. Поэтому при добавлении дополнительных полей или изменения порядка существующих придется следить, чтобы все инициализировалось в належащем порядке.