Урок №143. Конструкторы преобразования. Ключевые слова explicit и delete

  Юрий  | 

    | 

  Обновл. 19 Авг 2019  | 

 6913

 ǀ   5 

По умолчанию C++ обрабатывает любой конструктор как оператор неявного преобразования. Рассмотрим следующую программу:

Хотя функция makeNegative() ожидает объект класса Drob, мы передаём ей целочисленный литерал 7. Поскольку у класса Drob есть конструктор, который может принимать одно целочисленное значение (конструктор по умолчанию), то компилятор выполнит неявную конвертацию литерала 7 в объект класса Drob. Это делается путём выполнения копирующей инициализации параметра d функции makeNegative() с помощью конструктора Drob(int, int).

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

Copy constructor worked here!
-7/1

Неявное преобразование работает для всех видов инициализации (прямой, uniform и копирующей).

Конструкторы, которые используются в неявных преобразованиях, называются конструкторами преобразования (или ещё «конструкторами конвертации»). До C++11 конструкторами преобразования могли быть конструкторы только с одним параметром. Однако в C++11 это ограничение было снято (наряду с добавлением uniform инициализации), и конструкторы, имеющие несколько параметров, также уже могут быть конструкторами преобразования.

Ключевое слово explicit

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

В примере выше мы пытаемся инициализировать строку одним символом типа char. Поскольку char являются частью семейства целочисленных типов, то компилятор будет использовать конструктор преобразования SomeString(int) для неявного преобразования символа типа char в SomeString. Результатом является не то, что ожидается.

Один из способов решения этой проблемы — сделать конструктор явным, используя ключевое слово explicit (которое пишется перед именем конструктора). Явные конструкторы (с ключевым словом explicit) не используются для неявных конвертаций:

Программа выше не скомпилируется, так как SomeString(int) мы сделали явным, а другого конструктора преобразования, который выполнил бы неявную конвертацию 'a' в SomeString, компилятор просто не нашёл.

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

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

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

Ключевое слово delete


Ещё одним способом запретить конвертацию 'a' в SomeString (неявным или явным способом) является добавление закрытого конструктора SomeString(char):

Тем не менее, этот конструктор всё ещё может использоваться внутри класса (private закрывает доступ к данным только для объектов вне тела класса).

Лучшее решение — использовать ключевое слово delete (добавленное в C++11) для удаления этого конструктора:

После удаления функции, любое её использование вызовет ошибку компиляции.

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

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

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (39 оценок, среднее: 4,79 из 5)
Загрузка...

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

  1. Аватар Анастасия:

    Я правильно поняла, что explicit спасёт от неявных конвертаций только при копирующей инициализации? В топку тогда такое ключевое слово, которое только при одном из трёх способов помогает.
    Насчёт "= delete" тоже как-то резануло… Почему нельзя было поставить это слово перед конструктором, как обычно

  2. Аватар Валерий:

    Что-то пошло не так.
    Фраза "Это делается путем выполнения копирующей инициализацией параметра d функции makeNegative() с помощью конструктора Drob(int, int)." не соответствует действительности.
    Добавляем деструктор с выводом и отладочную печать в контрольных точках.

    И получаем результат:

    Constructor worked here!
    Enter
    Leave
    Copy constructor worked here!
    Destructor
    -7/1
    Destructor
    Exit

    При вызове makeNegative(7) работает обычный конструктор, создавая анонимный объект. Объект передается в функцию. В функции происходит обработка. При выходе выполняется копирующая инициализация второго анонимного объекта. Первый объект удаляется. Производится вывод. Удаляется второй анонимный объект.

    1. Аватар Анастасия:

      да, Ваша демонстрация показательней, чем в уроке.

  3. Аватар Slava:

    Привет! Мне нравится визуальный стиль оформления твоего листинга. Не мог бы ты скинуть данные по этому стилю, хочу его в CodeBlock засунуть.

    1. Юрий Юрий:

      Привет. Тема Monokai. Вот ссылка на цвета — Monokai.

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

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