Урок 119. Делегирующие конструкторы

   | 

   | 

 Обновлено 26 Фев 2018  | 

 2383

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

Здесь есть два конструктора: конструктор по умолчанию и конструктор, который принимает целочисленное значение. Поскольку часть, которая «часть кода X» требуется обоим конструкторам, то она дублируется в каждом из них.

А как вы уже могли догадаться, дублированный код — это то, чего следует избегать, поэтому давайте рассмотрим возможные способы решения этой проблемы.

Решение в C++11

Неплохо было бы, чтобы конструктор Boo(int) вызывал конструктор Boo() для выполнения кода части X.

или

Однако, если ваш компилятор не совместим с C++11 и вы попытаетесь вызвать один конструктор внутри другого конструктора, то это скомпилируется, но будет работать не так, как вы ожидаете, что приведет к вашему потраченному времени и усилиям в попытках разобраться, что не так.

До C++11 явный вызов одного конструктора из другого приводит к созданию временного объекта, который затем инициализируется с помощью конструктора этого объекта и отбрасывается, оставляя исходный объект неизменным.

Использование отдельной функции

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

Перепишем класс выше:

Здесь мы свели дублированный код к минимуму.

Кроме того, вы можете оказаться в ситуации, когда нужно будет написать функцию-член для повторной инициализации класса обратно до значений по умолчанию. Поскольку у вас, вероятно, уже есть конструктор, который это делает, то у вас может возникнуть соблазн попытаться вызвать конструктор из вашей функции-члена. Однако это приведет к неожиданным результатам. Многие разработчики просто копируют код из конструктора в функцию инициализации – это сработает, но приведет также к дублированию кода. Лучшим решением будет переместить код из конструктора в вашу новую функцию и заставить конструктор вызывать вашу новую функцию для выполнения инициализации:

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

Делегирующие конструкторы в C++11

Начиная с C++11, конструкторам разрешено вызывать другие конструкторы. Этот процесс называется делегированием конструкторов (или еще цепочкой конструкторов).



Чтобы один конструктор вызывал другого, нужно просто сделать вызов этого конструктора в списке инициализации членов. Например:

Всё работает как нужно. Убедитесь, что вы вызываете конструктор из списка инициализации членов, а не из тела конструктора.

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

Этот класс имеет 2 конструктора, один из которых вызывает другого. Таким образом, количество дублированного кода минимизируется (нам нужно записать только одно тело конструктора вместо двух).

Несколько заметок о делегирующих конструкторах

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

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (24 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО