Что произойдет если программист не объявит в коде класса конструктор и деструктор

Обновлено: 28.04.2024

Возможно вы заметили, что определяя класс, мы не можем инициализировать его поля (члены) в самом определении. Можно присвоить им значение, написав соответствующий метод класса и вызвав его, после создания объекта вне класса. Такой способ не совсем удобен, так как объявляя, допустим, 33 объекта класса нам придется 33 раза вызывать метод, который присваивает значения полям класса. Поэтому, как правило, для инициализации полей класса, а так же для выделения динамической памяти, используется конструктор.

Конструктор (от construct – создавать) – это особый метод класса, который выполняется автоматически в момент создания объекта класса. То есть, если мы пропишем в нем, какими значениями надо инициализировать поля во время объявления объекта класса, он сработает без “особого приглашения”. Его не надо специально вызывать, как обычный метод класса.

В строках 11 – 17 определяем конструктор: имя должно быть идентично имени класса; конструктор НЕ имеет типа возвращаемого значения (void в том числе). Один объект объявляется сразу во время определения класса – строка 25. При запуске программы, конструктор этого объекта сработает даже до входа в главную функцию. Это видно на следующем снимке:

конструктор класса c++, деструктор класса c++, конструктор и деструктор класса с++

программа еще не дошла до выполнения строки 29 setlocale ( LC_ALL , "rus" ) ; , а конструктор уже “отчитался”, что сработал (кириллица отобразилась некорректно). В строке 30 – смотрим, что содержат поля класса. Второй раз конструктор сработает в строке 32, во время создания объекта obj2 .

Деструктор (от destruct – разрушать) – так же особый метод класса, который срабатывает во время уничтожения объектов класса. Чаще всего его роль заключается в том, чтобы освободить динамическую память, которую выделял конструктор для объекта. Имя его, как и у конструктора, должно соответствовать имени класса. Только перед именем надо добавить символ ~

Добавим деструктор в предыдущий код. И создадим в классе два конструктора: один будет принимать параметры, второй – нет.

Нигде не утверждается, что объект должен быть инициализирован, и программист может забыть инициализировать его или сделать это дважды.
ООП дает возможность программисту описать функцию, явно предназначенную для инициализации объектов. Поскольку такая функция конструирует значения данного типа, она называется конструктором . Конструктор всегда имеет то же имя, что и сам класс и никогда не имеет возвращаемого значения. Когда класс имеет конструктор, все объекты этого класса будут проинициализированы.

Если конструктор требует аргументы, их следует указать:

date today = date(6,4,2014); // полная форма
date xmas(25,12,0); // сокращенная форма
// date my_burthday; // недопустимо, опущена инициализация

Если необходимо обеспечить несколько способов инициализации объектов класса, задается несколько конструкторов:

class date <
int month, day, year;
public :
date( int , int , int ); // день месяц год
date( char *); // дата в строковом представлении
date(); // дата по умолчанию: сегодня
>;

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

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

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

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

class date
int month, day, year;
public :
date( int , int , int );
date( char *);
date(); // конструктор по умолчанию
>;

При создании объекта вызывается конструктор, за исключением случая, когда объект создается как копия другого объекта этого же класса, например:

Однако имеются случаи, в которых создание объекта без вызова конструктора осуществляется неявно:

  • формальный параметр – объект, передаваемый по значению, создается в стеке в момент вызова функции и инициализируется копией фактического параметра;
  • результат функции – объект, передаваемый по значению, в момент выполнения оператора return копируется во временный объект, сохраняющий результат функции.

Во всех этих случаях транслятор не вызывает конструктора для вновь создаваемого объекта:

  • date2 в приведенном определении;
  • для создаваемого в стеке формального параметра;
  • для временного объекта, сохраняющего значение, возвращаемое функцией.

Вместо этого в них копируется содержимое объекта-источника:

  • date1 в приведенном примере;
  • фактического параметра;
  • объекта-результата в операторе return .

Конструктор копии

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

Деструкторы

Определяемый пользователем класс имеет конструктор, который обеспечивает надлежащую инициализацию. Для многих типов также требуется обратное действие. Деструктор обеспечивает соответствующую очистку объектов указанного типа. Имя деструктора представляет собой имя класса с предшествующим ему знаком «тильда» ~ . Так, для класса X деструктор будет иметь имя ~X() . Многие классы используют динамическую память, которая выделяется конструктором, а освобождается деструктором.

class date
int day, year;
char *month;
public :
date( int d, char * m, int y)
day = d;
month = new char [strlen(m)+1];
strcpy_s(month, strlen(m)+1,m);
year = y;
>
~date() < delete [] month; >// деструктор
>;

Поля, имеющие тип класса

Пусть имеется класс vect , реализующий защищенный массив, и необходимо хранить несколько значений для каждого такого массива: возраст, вес и рост группы лиц. Группируем 3 массива внутри нового класса.

Конструктор нового класса имеет пустое тело и список вызываемых конструкторов класса vect , перечисленных после двоеточия (:) через запятую (,). Они выполняются с целым аргументом i , создавая 3 объекта класса vect: a, b, c .

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

Здравствуйте, у меня такой вопрос. В коде я не нашел сам деструктор. Он создается и запускается сам после выхода из блока main ?

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

Наследование

Иерархия классов позволяет определять новые классы на основе уже имеющихся. Имеющиеся классы обычно называют базовыми (иногда порождающими), а новые классы, формируемые на основе базовых, – производными (порожденными, классами-потомками или наследниками).


При наследовании некоторые имена методов (функций-членов) и полей (данных-членов) базового класса могут быть по-новому определены в производном классе. В этом случае соответствующие компоненты базового класса становятся недоступными из производного класса. Для доступа из производного класса к компонентам базового класса, имена которых повторно определены в производном, используется операция разрешения контекста ::

Для порождения нового класса на основе существующего используется следующая общая форма

При объявлении порождаемого класса МодификаторДоступа может принимать значения public , private , protected либо отсутствовать, по умолчанию используется значение private . В любом случае порожденный класс наследует все члены базового класса, но доступ имеет не ко всем. Ему доступны общие ( public ) члены базового класса и недоступны частные ( private ).

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

Члены класса с доступом protected видимы в пределах класса и в любом классе, порожденном из этого класса.

Общее наследование

При общем наследовании порожденный класс имеет доступ к наследуемым членам базового класса с видимостью public и protected . Члены базового класса с видимостью private – недоступны.

Спецификация доступа внутри класса в порожденном классе вне класса
private +
protected + +
public + + +

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

Порожденный класс наследует все данные класса student (строка 13), имеет доступ к protected и public — членам базового класса. В новом классе добавлено два поля данных (строки 16, 17), и порожденный класс переопределяет функцию print() (строки 20, 39-43).

Конструктор для базового класса вызывается в списке инициализации (строка 29).

Но что происходит, когда мы присваиваем указателю класса student ссылку на объект класса grad_student (строка 55)? В этом случае происходит преобразование указателей, и в строке 56 вызывается уже функция print() класса student .


Указатель на порожденный класс может быть неявно передан в указатель на базовый класс. А указатель на порожденный класс может указывать только на объекты порожденного класса. То есть обратное преобразование недопустимо

Неявные преобразования между порожденным и базовым классами называются предопределенными стандартными преобразованиями :

  • объект порожденного класса неявно преобразуется к объекту базового класса.
  • ссылка на порожденный класс неявно преобразуется к ссылке на базовый класс.
  • указатель на порожденный класс неявно преобразуется к указателю на базовый класс.

Частное наследование

Порожденный класс может быть базовым для следующего порождения. При порождении private наследуемые члены базового класса, объявленные как protected и public , становятся членами порожденного класса с видимостью private . При этом члены базового класса с видимостью public и protected становятся недоступными для дальнейших порождений. Цель такого порождения — скрыть классы или элементы классов от использования их в дальнейших порождениях. При порождении private не выполняются предопределенные стандартные преобразования:

Однако порождение private позволяет отдельным элементам базового класса с видимостью public и protected сохранить свою видимость в порожденном классе. Для этого необходимо

  • в части protected порожденного класса указать те наследуемые члены базового класса с видимостью protected , уточненные именем базового класса, для которых необходимо оставить видимость protected и в порожденном классе;
  • в части public порожденного класса указать те наследуемые члены базового класса с видимостью public , уточненные именем базового класса, для которых необходимо оставить видимость public и в порожденном классе.

class X
private :
int n;
protected :
int m;
char s;
public :
void func( int );
>;
class Y : private X
private :
.
protected :
.
X::s;
public :
.
X::func();
>;

Возможен и третий вариант наследования – с использованием модификатора доступа protected .

Доступ к элементам базового класса из производного класса, в зависимости от модификатора наследования:

Конструкторы и деструкторы при наследовании

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

Если и у базового и у производного классов есть конструкторы и деструкторы, то конструкторы выполняются в порядке наследования, а деструкторы – в обратном порядке. То есть если А – базовый класс, В – производный из А , а С – производный из В ( А-В-С ), то при создании объекта класса С вызов конструкторов будет иметь следующий порядок:

  • конструктор класса А
  • конструктор класса В
  • конструктор класса С .

Вызов деструкторов при удалении этого объекта произойдет в обратном порядке:

  • деструктор класса С
  • деструктор класса В
  • деструктор класса А .

Поскольку базовый класс «не знает» о существовании производного класса, любая инициализация выполняется в нем независимо от производного класса, и, возможно, становится основой для инициализации, выполняемой в производном классе. Поскольку базовый класс лежит в основе производного, вызов деструктора базового класса раньше деструктора производного класса привел бы к преждевременному разрушению производного класса.

Конструкторы могут иметь параметры. При реализации наследования допускается передача параметров для конструкторов производного и базового класса. Если параметрами обладает только конструктор производного класса, то аргументы передаются обычным способом. При необходимости передать аргумент из производного класса конструктору родительского класса используется расширенная запись конструктора производного класса:

КонструкторПроизводногоКласса (СписокФормальныхАргументов)
: КонструкторБазовогоКласса (СписокФактическихАргументов)
< // тело конструктора производного класса >

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

Конструктор производного класса не должен использовать все аргументы, часть предназначены для передачи в базовый класс (строка 29, см. код выше). В расширенной форме объявления конструктора производного класса описывается вызов конструктора базового класса.

Здравствуйте! а подскажите, пожалуйста, как я могу объявить неполный наследуемый класс? Например, у меня есть class a b class b, наследуемый откласса а. я хочу неполно объявить класс b перед классом а. как это синтаксически сделать? нигде не могу найти инфу об этом.

Класс - ключевое понятие в объектно-ориентированном программировании, и без знаний о классах невозможно создавать рабочие программы на языке С++. Проверьте Ваши знания по теме, ответив на вопросы этого теста!



структура, описывающая функции, необходимые для работы программы

тип данных, определяемый программистом и описывающий объект и методы работы с ним

любой тип данных, определяемый программистом

функция, работающая с классом

сущность, имеющая заданные значения свойств и методов для работы с ними

Какие методы присутствуют в любом классе?

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

Никакие методы не являются обязательными

Что такое конструктор?

Специальный метод, который вызывается при создании нового объекта для автоматической инициализации переменных

Функция, которая создает экземпляр класса

Класс, который содержит все необходимые для работы методы

Что произойдет, если программист не объявит в коде класса конструктор и деструктор?

Класс не будет доступен остальной программе

Конструктор и деструктор будут представлены в неявном виде

Как правильно явно объявить деструктор?

Какое значение возвращает деструктор?

На картинке представлен код, в котором объявлен конструктор. Правильно ли поступил программист?

И конструктор, и деструктор должны объявляться в разделе public, не private.

Выберите определение полиморфизма:

Первое определение - полиморфизм, второе - наследование, третье - инкапсуляция.

свойство классов, позволяющее использовать объекты классов с одинаковым интерфейсом без информации о типе и внутренней структуре объекта

свойство, позволяющее создать новый класс-потомок на основе уже существующего, при этом все характеристики класса родителя присваиваются классу-потомку

это свойство, позволяющее объединить в классе и данные, и методы, работающие с ними и скрыть детали реализации от пользователя

В какой строке в данном коде объявляется экземпляр класса MyClass?

Экземпляр класса создается в строке 16

Программист написал простую программу, приведенную на изображении, но забыл дописать строчку, которая выводит сумму на экран. Что нужно написать в 25 строке?

Выберите правильное утверждение для модификатора protected

Private запрещает доступ за пределами класса, public не ограничивает доступ вообще, а protected разрешает только внутри самого класса и его наследниках.

Методы и переменные доступны для использования как внутри класса, так и извне.

Методы и переменные доступны для использования только внутри класса.

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

Можно ли объявить класс без методов?

Что такое наследование?

передача переменных в другой класс

механизм создания нового класса на основе уже существующего

способ применения класса в различных программах

На изображении представлен отрывок кода, в котором объявляется класс policeman. Какое утверждение верно?

класс policeman является наследником класса worker

класс worker является производным от класса policeman

класс worker является наследником класса policeman

Вы обладаете начальными знаниями по теме

Вам еще многое предстоит узнать по теме классов! Не упускайте важные детали и тщательно изучите все аспекты: успешное освоение этой темы - залог удачного написания программ различной сложности в дальнейшем. Удачи! Покажите тест друзьями и узнайте, как хорошо они разбираются в классах в С++!

Вы обладаете средними знаниями по теме

Вы разбираетесь в основах, но многое еще не знаете. Читайте книги и статьи, разбирайте задачи, пробуйте написать простые программы, и только так Вы сможете усвоить тему на отлично! Помните, что без классов в объекто-ориентированном программировании никак нельзя, и уделите теме должное внимание. Удачи! Покажите тест друзьями и узнайте, как хорошо они разбираются в классах в С++!

Вы в совершенстве знаете тему!

Вы отлично усвоили материал и теперь без проблем разбираетесь в классах. Пора приступать к следующей теме! Стоит иногда повторять материал, ведь классы - основа объектно-ориентированного программирования. Удачи! Покажите тест друзьями и узнайте, как хорошо они разбираются в классах в С++!

Конструктор - блок инструкций, вызываемый при создании объекта класса.

Деструктор - блок инструкций, вызываемый при уничтожении объекта класса.

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

Назначение конструктора: присвоение каких-то значений полям, выделение памяти, открытие файлов и установление сетевых соединений.

Назначение деструктора: соответственно, наоборот очистка памяти и сохранение файлов.

Параметры конструктора. Конструктор может принимать какие-то значения в качестве аргументов - например, для установки значений полям. Также возможно создание нескольких конструкторов с разными параметрами. Деструктор всегда один и без параметров.

Оформление конструктора (внутри класса):

Оформление деструктора (внутри класса):

Пример вызова конструктора:

Чтобы исключить вызов конструктора через присваивание, как показано в последнем примере, к конструктору дописывается ключевое слово explicit (перед конструктором).

Для конструктора, конструкторов копирования и перемещения, а также деструктора справедливо следующее: если программист не написал их сам, то компилятор допишет их за него. Такие конструкторы(деструкторы) называются неявными. Также важно понимать, что конструктор, декструтор, к.копирования и к.перемещения должны иметь доступ модификатор доступа public.

Это конструктор вида (для случая внутри класса):

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

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

Благодаря этому конструктору, мы можем, например, писать вот так:

В данном примере для a2 и a3 будет вызван конструктор копирования, который скопирует каждое поле a1.

Самое главное про конструктор копирования: если вы оставили для полей-указателей простое копирование, то, когда в первом объекте (который мы копировали) они будут почищены (например, деструктором), во втором они также почистятся, а этого вы, скорее всего, не задумываете.

Если мы захотим сломать конструктор копирования, указав явно только один его вариант, который принимает не только ссылку, но и другие аргументы, то программа сама додумает за нас самый просто конструктор копирования с единственным аргументом (ссылкой). И пример, приведённый выше, всё ещё будет работать. А вот если мы сами напишем конструктор копирования с одним аргументом (ссылкой) и добавим к нему слово explicit, то пример работать перестанет, так как из-за третьей строчки программа не скомпилируется.

Также обратите внимание, что переопределив конструктор копирования вы никак не затронете обычные операции присваивания.

Если мы переопределили конструктор копирования, чтобы он, например, менял местами поля и дописывал всякие нехорошие слова к полям-строкам, а затем запустили пример, приведённый выше, то эти действия произведутся только для a1, а объект a2 будет идентичен объекту b.

Это конструктор вида (для случая внутри класса):

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

Читайте также: