Урок 116. Конструкторы

   ⁄ 

 Обновлено 19 Фев 2018  ⁄ 

 ⁄   2 

⁄   2068

Когда все члены класса (или структуры) являются открытыми, то мы можем инициализировать класс (или структуру) напрямую, используя список инициализаторов или uniform инициализацию (в C++11):

Однако, как только мы сделаем какие-либо переменные-члены класса закрытыми, то мы больше не сможем инициализировать их напрямую. Здесь есть смысл: если вы не можете напрямую обращаться к переменной (потому что она закрыта), то вы и не должны иметь возможность напрямую её инициализировать.

Как тогда инициализировать класс с закрытыми переменными-членами? Использовать конструкторы.

Конструкторы

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

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

  Конструкторы всегда должны иметь то же имя, что и класс (учитывается верхний и нижний регистры).

  Конструкторы не имеют типа возврата (даже void-а).



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

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

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

Пример класса с конструктором по умолчанию:

Этот класс содержит дробь в виде отдельных значений типа int. Конструктор по умолчанию называется Fraction (как и класс).

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

Результат выполнения программы выше:

0/1

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

Конструктор с параметрами. Прямая и uniform инициализации

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

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

Как использовать конструктор с параметрами? Всё просто! Прямая инициализация:

Здесь мы инициализировали нашу дробь числами 4 и 5, результат — 4/5!

В C++11 мы также можем использовать uniform инициализацию:

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

Значения по умолчанию для конструкторов работают точно так же, как и для любой другой функции, поэтому в примере выше, когда мы вызываем seven(7), вызывается Fraction(int, int), второй параметр которого равен 1 (значение по умолчанию).

Правило: Используйте прямую или uniform инициализацию для объектов ваших классов.

Классы. Копирующая инициализация

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

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

Правило: Не используйте копирующую инициализацию для объектов ваших классов.

Сокращение количества конструкторов

В примере выше с классом Fraction и двумя конструкторами: по умолчанию и с параметрами — конструктор по умолчанию на самом деле лишний. Мы могли бы упростить этот класс следующим образом:

Хотя этот конструктор по-прежнему является конструктором по умолчанию, он теперь определен таким образом, что может принимать одно или два значения, предоставленные пользователем.

На практике старайтесь сокращать количество конструкторов вашего класса.



Неявно генерируемый конструктор по умолчанию

Если ваш класс не имеет других конструкторов, то C++ автоматически сгенерирует для вашего класса открытый конструктор по умолчанию. Его иногда называют неявным конструктором (или неявно сгенерированным конструктором).

Рассмотрим следующий класс:

У этого класса нет конструктора. Поэтому компилятор сгенерирует следующий, идентичен по выполнению, конструктор:

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

Хотя вы не можете увидеть неявно сгенерированный конструктор, но его существование можно доказать:

Код выше скомпилируется, поскольку в объекте date сработает неявный конструктор (который является открытым).

Если ваш класс имеет другие конструкторы, то неявно генерируемый конструктор создаваться не будет. Например:

Вообще, рекомендуется всегда создавать по крайней мере один конструктор в классе. Это позволит вам контролировать процесс создания объектов вашего класса, и предотвратит возникновение потенциальных проблем после добавления других конструкторов.

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

Классы, содержащие другие классы

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

Это можно продемонстрировать следующим образом:

Результат выполнения программы выше:

A
B

При создании переменной b вызывается конструктор B(). Прежде чем тело конструктора выполнится, m_a инициализируется, вызывая конструктор по умолчанию класса A. Таким образом выведется «A». Затем управление возвратится обратно к конструктору B, и тело конструктора B начнет свое выполнение.

Здесь есть смысл, так как конструктор B() может захотеть использовать переменную m_a, поэтому сначала нужно инициализировать m_a!

Тест

Задание №1

a) Напишите класс Ball. Ball должен иметь две закрытые переменные-члены со значениями по умолчанию:

  m_color («Red»);

  m_radius (20.0).

В Ball-е должны быть конструкторы:

  для установления значения только m_color;

  для установления значения только m_radius;

  для установления значений и m_radius, и m_color;

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

Не используйте параметры по умолчанию для конструкторов. Напишите еще функцию для вывода цвета (m_color) и радиуса (m_radius) шара (объекта класса Ball).

Следующий код функции main():

должен производить следующий результат:

color: red, radius: 20
color: black, radius: 20
color: red, radius: 30
color: black, radius: 30

Ответ а)

b) Теперь обновите ваш код с использованием конструкторов с параметрами по умолчанию. Постарайтесь использовать как можно меньше конструкторов.

Ответ b)

Задание №2

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

Ответ

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

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

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

Комментариев: 2

  1. Анатолий:

    В задании переменные должны быть со значениями по умолчанию. Все работает, такой код допустим?

    1. Li4ik:

      Если вы указали значения переменным-членам при их объявлении, тогда зачем вы пишите пустой конструктор Ball() и просто перечисляете эти переменные-члены? Остальное может быть, только желательно было бы еще указывать значение другой переменной в теле конструктора с одним параметром.

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

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

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

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

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