Неявное VS явное преобразование - PullRequest
17 голосов
/ 18 августа 2011

Стандартная библиотека C ++ Николая М. Йосуттиса утверждает:

Существует небольшая разница между

X x;
Y y(x) //explicit conversion

и

X x;
Y y = x; //implicit conversion

Следующие слова: "Первый создает новый объект типа Y с помощью явного преобразования из типа X, тогда как второй создает новый объект типа Y с помощью неявного преобразования. "

Я немного запутался в понятияхЯвное явное против неявного преобразования.В обоих случаях вы берете X и помещаете его в Y как таковой - один использует конструктор Y, а другой использует оператор присваивания.

В чем разница в том, как обрабатывается преобразование в этих двух случаях, что делает его явным / неявным, и как это связано с созданием конструктора класса, определенного с помощью «явного» ключевого слова, если вообще?

Ответы [ 4 ]

28 голосов
/ 18 августа 2011

один использует конструктор Y, а другой - оператор присваивания.

Нет.Во втором случае это не присваивание, это инициализация , оператор присваивания (operator=) никогда не вызывается;вместо этого вызывается не explicit однопараметрический конструктор (который принимает тип X в качестве параметра).

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

В любом случае, две написанные вами формы инициализации отличаются тем, что в первом случае вы явно вызываете конструктор, и, следовательно, любойконструктор приемлем;во втором случае вы вызываете конструктор неявно , поскольку вы используете не «классический» синтаксис конструктора, а синтаксис инициализации.

В этом случае только одинконструкторы параметров, не отмеченные explicit, являются приемлемыми.Такие конструкторы некоторые люди называют «конвертирующими» конструкторами, потому что они участвуют в неявных преобразованиях.

Как указано в этом другом ответе , любой конструктор, не помеченный как explicit, может принимать участие.в неявном преобразовании, например, для преобразования объекта, переданного в функцию, в тип, ожидаемый такой функцией.На самом деле, вы можете сказать, что это то, что происходит во втором примере: вы хотите инициализировать (= создать со значением, скопированным из другого места) y с x, но сначала x необходимо преобразовать в тип Y, что делается с помощью неявного конструктора.

Этот тип неявного преобразования часто желателен: подумайте, например, о строковом классе, который имеет конвертирующий (т.е. не explicit) конструктор из const char *:любая функция, которая получает параметр string, также может быть вызвана с "нормальной" C-строкой: из-за конструктора преобразования вызывающий будет использовать C-строки, вызываемый будет получать объект string.

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

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

Проще говоря, может также случиться, что некоторые конструкторы могут быть очень тяжелыми, поэтому разработчик класса может захотеть убедиться, что они вызываютсяв явном виде.В этих случаях конструктор помечается как explicit, поэтому его можно использовать только тогда, когда он вызывается «явно как конструктор», и он не участвует в неявных преобразованиях.

3 голосов
/ 18 августа 2011

Первая форма прямая инициализация .Вторым является копирование инициализации .

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

Рассмотрим третью возможность - инициализацию копирования, но преобразование явное:

Y y = Y(x);

или

Y y = (Y)x;
2 голосов
/ 18 августа 2011

один использует оператор присваивания, хотя

Нет, это не так.Он вызывает конструктор напрямую.

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

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

int i = 0;
i = i >> MyUDT();

Ой, подождите - почему это даже компилируется?Вы не можете сдвинуть MyUDT вообще!Компилируется, потому что bool является целочисленным типом.Компилятор неявно преобразует его в тип bool, а затем в нечто, что может быть смещено.Приведенный выше код явно тупой - мы только хотим, чтобы люди могли конвертировать в bool , а не в bool и во все остальное, что bool может захотеть сделать.

Вот почему явнооператоры преобразования были добавлены в C ++ 0x.

0 голосов
/ 26 июля 2016

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

int iVal = 100; double dVal = iVal;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...