один использует конструктор Y, а другой - оператор присваивания.
Нет.Во втором случае это не присваивание, это инициализация , оператор присваивания (operator=
) никогда не вызывается;вместо этого вызывается не explicit
однопараметрический конструктор (который принимает тип X
в качестве параметра).
Важна разница между инициализацией и присваиванием: в первом случае новый объектсоздается, и он начинает свою жизнь со значения, с которым он инициализируется (поэтому и вызывается конструктор), тогда как присваивание происходит, когда объект присваивается (~ копируется) объекту, который уже существует и уже находится в определенном состоянии .
В любом случае, две написанные вами формы инициализации отличаются тем, что в первом случае вы явно вызываете конструктор, и, следовательно, любойконструктор приемлем;во втором случае вы вызываете конструктор неявно , поскольку вы используете не «классический» синтаксис конструктора, а синтаксис инициализации.
В этом случае только одинконструкторы параметров, не отмеченные explicit
, являются приемлемыми.Такие конструкторы некоторые люди называют «конвертирующими» конструкторами, потому что они участвуют в неявных преобразованиях.
Как указано в этом другом ответе , любой конструктор, не помеченный как explicit
, может принимать участие.в неявном преобразовании, например, для преобразования объекта, переданного в функцию, в тип, ожидаемый такой функцией.На самом деле, вы можете сказать, что это то, что происходит во втором примере: вы хотите инициализировать (= создать со значением, скопированным из другого места) y
с x
, но сначала x
необходимо преобразовать в тип Y
, что делается с помощью неявного конструктора.
Этот тип неявного преобразования часто желателен: подумайте, например, о строковом классе, который имеет конвертирующий (т.е. не explicit
) конструктор из const char *
:любая функция, которая получает параметр string
, также может быть вызвана с "нормальной" C-строкой: из-за конструктора преобразования вызывающий будет использовать C-строки, вызываемый будет получать объект string
.
Тем не менее, в некоторых случаях конструкторы с одним параметром могут не подходить для преобразования: обычно это происходит, когда их единственный параметр концептуально не «преобразован» в тип создаваемого объекта, но это просто параметр для конструкции;Подумайте, например, об объекте файлового потока: возможно, у него будет конструктор, который принимает имя открываемого файла, но нет смысла говорить, что такая строка «конвертируется» в поток, который работает с этим файлом.
Вы также можете найти несколько более сложных сценариев, в которых эти неявные преобразования могут полностью испортить поведение, которое программист ожидает от разрешения перегрузки;примеры этого можно найти в ответах ниже того, который я связал выше.
Проще говоря, может также случиться, что некоторые конструкторы могут быть очень тяжелыми, поэтому разработчик класса может захотеть убедиться, что они вызываютсяв явном виде.В этих случаях конструктор помечается как explicit
, поэтому его можно использовать только тогда, когда он вызывается «явно как конструктор», и он не участвует в неявных преобразованиях.