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

Читать тему до конца.

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

Сложнее понять, что именно происходит в таком коде и какие эффекты получаются.

Эффект можно посмотреть:

Происходящий процесс можно назвать инициализацией объекта obj конструктором класса с параметром, которому отдаётся целое число 100.

Превращается в

Происходит эффект неявного приведения целочисленного типа в тип MyClass.

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

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

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

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

Ниже приводится пример, утрированный в пользу ясности соли момента:
В каком-то большом проекте имеется класс String и отдельные функции:

Всё успешно работает, и, в один момент, сообщество, имеющее отношение к проекту, решает переписать некоторые места программы, потому что код можно переработать в лучшую сторону. Решение принято, работа проделана.
Функция
void do_something(int); была заменена на void do_something_with_int(int);
И здесь маскируется ошибка. Она ждёт момента, чтобы сделать вам плохо. Выжидает этот момент долго и упрямо. И дождавшись самого неподходящего для вас времени, выскакивает с криком: "А вот и я!".
Ошибка маскируется, код прекрасно выполняется.

Изменение ==>

Вот такая гнильца имеется у этого конвертирующего конструктора. Эти два кода дают разный эффект.

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

S1 и S2 объединяются в одно S для более короткого объяснения.

В этом маленьком коде может быть непонятно, что происходит. С одной стороны поведение должно быть одинаковым, в S присвоить 5, с другой стороны это может обозначать выделить в S пять мест. И с какой стороны ни посмотри, удобней будет, если в обоих случаях будет срабатывать одно и то же, так меньше шансов перепутать первое со вторым, но нет же, у нас может быть совершенно два разных действия: в первом случае в строку записывается число, которое путём всяческих преобразований таки оказывается представлено в символьном виде, а во втором случае просто выделяется память, но ничего в S не присваивается. Возможны и другие варианты развития событий. Голова от этого болеть не начинает? Нет? Значит, вы не имели дела с кашей и плохо себе представляете, как это напрягает, думать о каждой мелочи. Код должен быть говорящим, и чем он красноречивее, тем лучше всем.

Суть в том, что человек может иметь желание избежать подобной каши, и сделать это проще всего путём запрещения оператора присваивания. Но как его запретить? Думало сообщество, думало, и решило, что конвертирующий конструктор — дело тонкое, иногда мешает. Поэтому в язык С++ было введено ключевое слово explicit, которое немного кастрирует конвертирующий конструктор, в результате чего конвертирующий конструктор превращается в конструктор неконвертирующий, в обычный то есть, в такой, каким должен быть по определению. Использование ключевого слова explicit помогает избегать нежелательных преобразований и помогает не совершить ошибку, которую очень сложно найти.

  • Помните! Если вы используете конструтор с одним параметром, то используете ключевое слово explicit, которое поможет вам избежать возможных проблем

Не только конструктор с одним параметром, но и конструктор с несколькими параметрами, если только первый обычный, а остальные все по умолчанию, или же все они параметры по умолчанию.

Вот кусочек этой схемы:

explicit можно не использовать, если оператор присваивания не лишён смысла. Возьмём для примера строку. Для строки в С++ может быть не лишено смысла такое выражение:

В наш класс "Строка" присваивается Си-строка. Нашей строке str кормится Си-строка, что вполне логично и не лишено смысла, поэтому конструктор, принимающий Си-строку в классе String предварять ключевым словом explicit не обязательно нужно.

В этом примере коротко показано то, о чём долго писалось выше. Если лишено смысла использовать оператор присваивания, то explicit выполняет роль шлагбаума для конструктора.

  • Использование explicit — это строгое указание конструктору, принимающему один параметр, не чудить

Большое спасибо DrOffset, эта статья написана благодаря его ответу на форуме cyberforum

Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

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

Ваш e-mail не будет опубликован.

Поиск

 
     

Случайная книга в электронном формате

Яндекс.Метрика
НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Cидят двa aдминa нa рaботе, грустят, зaходит третий: - Че тaкие грустные? - Дa, вчерa пиво пили и пaроли меняли...

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок