c++ - variable - Conversión explícita VS explícita
virtual variable in c++ (4)
La biblioteca estándar de C ++ por Nicolai M. Josuttis afirma:
Hay una pequeña diferencia entre
X x;
Y y(x) //explicit conversion
y
X x;
Y y = x; //implicit conversion
Siguiendo para decir: "El primero crea un nuevo objeto de tipo Y utilizando una conversión explícita del tipo X, mientras que el último crea un nuevo objeto de tipo Y utilizando una conversión implícita".
Estoy un poco confundido acerca de los conceptos de conversión explícita vs implícita, supongo. En ambos casos, toma una X y la empuja hacia una Y per se: una usa el constructor de una Y y la otra usa el operador de asignación.
¿Cuál es la diferencia en cómo se trata la conversión en estos dos casos, qué lo hace explícito / implícito, y cómo se relaciona esto con hacer que un constructor de clase se defina con la palabra clave "explícita", en todo caso?
aunque uno usa el operador de asignación
No, no lo hace. Llama al constructor directamente.
La razón por la cual uno es explícito y otro implícito es porque las conversiones implícitas pueden ocurrir cuando no quiere que lo hagan. Los explícitos no pueden. El ejemplo más fácil de esto es bool.
Digamos que usted inventa algún tipo que puede ser verdadero o falso, como un puntero. Luego digamos que decide que para hacer la vida más fácil para sus usuarios, deje que se convierta a bool implícitamente. Esto es genial, hasta el punto en que uno de sus usuarios hace algo tonto.
int i = 0;
i = i >> MyUDT();
Oh, espera, ¿por qué se compila eso? ¡No puedes cambiar un MyUDT en absoluto! Se compila porque bool
es un tipo integral. El compilador lo convirtió implícitamente en un bool, y luego en algo que se puede cambiar. El código anterior es descaradamente tonto; solo queremos que las personas puedan convertirse a un bool , no a un bool y cualquier otra cosa que un bool pueda querer hacer.
Esta es la razón por la que se agregaron operadores de conversión explícitos a C ++ 0x.
uno usa el constructor de una Y y el operador de asignación.
No En el segundo caso, no es una asignación, es una inicialización , el operador de asignación ( operator=
) nunca se llama; en su lugar, se llama a un constructor no explicit
un parámetro (que acepta el tipo X
como parámetro).
La diferencia entre la inicialización y la asignación es importante: en el primer caso, se está creando un nuevo objeto y comienza su vida con el valor con el que se está inicializando (de ahí el motivo por el que se llama a un constructor), mientras que la asignación ocurre cuando un objeto se asigna (~ se copia) a un objeto que ya existe y ya está en un estado definido .
De todos modos, las dos formas de inicialización que escribiste difieren en el hecho de que en el primer caso estás llamando explícitamente a un constructor, y por lo tanto cualquier constructor es aceptable; en el segundo caso, está llamando implícitamente a un constructor, ya que no está usando la sintaxis de constructor "clásica", sino la sintaxis de inicialización.
En este caso, solo se aceptan constructores de un parámetro que no estén marcados con explicit
. Tales constructores son llamados por algunas personas para "convertir" constructores, porque están involucrados en conversiones implícitas.
Como se especifica en esta otra respuesta , cualquier constructor que no esté marcado como explicit
puede participar en una conversión implícita para, por ejemplo, convertir un objeto pasado a una función al tipo esperado por dicha función. En realidad, puede decir que es lo que sucede en su segundo ejemplo: desea inicializar (= crear con un valor copiado de otro lugar) y
con x
, pero primero se debe convertir x
al tipo Y
, lo que se hace con el constructor implícito .
Este tipo de conversión implícita suele ser deseable: piense, por ejemplo, en una clase de cadena que tenga un constructor de conversión (es decir, no explicit
) de un const char *
: cualquier función que reciba un parámetro de string
también puede llamarse con una C "normal" -string: debido al constructor de conversión, la persona que llama usará C-strings, el que recibe su objeto string
.
Aún así, en algunos casos, los constructores de un solo parámetro pueden no ser apropiados para la conversión: generalmente esto sucede cuando su único parámetro no se "convierte" conceptualmente al tipo de objeto que se está creando, pero es solo un parámetro para la construcción; por ejemplo, piense en un objeto de flujo de archivos: probablemente tendrá un constructor que acepte el nombre del archivo para abrir, pero no tiene sentido decir que dicha cadena se "convierte" a un flujo que funciona en ese archivo.
También puede encontrar algunos escenarios más complejos donde estas conversiones implícitas pueden alterar completamente el comportamiento que el programador espera de la resolución de sobrecarga; Se pueden encontrar ejemplos de esto en las respuestas debajo de la que he vinculado arriba.
Más simplemente, también puede suceder que algunos constructores puedan ser muy pesados, por lo que el diseñador de la clase puede querer asegurarse de que se invocan explícitamente. En estos casos, el constructor está marcado como explicit
, por lo que solo se puede usar cuando se lo llama "explícitamente como constructor" y no participa en las conversiones implícitas.
El casting implícito no requiere ningún operador de casting. Esta conversión se usa normalmente cuando se convierten datos de tipos integrales más pequeños a tipos más grandes o derivados al tipo base.
int iVal = 100; doble dVal = iVal;
El constructor de conversión explícita se prefiere al operador de conversión implícito porque en este último caso hay una llamada adicional al constructor de copia. Conversiones implícitas y explícitas
La primera forma es la inicialización directa . El segundo es la inicialización de la copia .
La inicialización de la copia llama implícitamente a un constructor de conversión u operador de conversión y luego llama explícitamente a un constructor de copia (la llamada del constructor de copia puede ser elidida, pero aún debe realizarse una verificación de accesibilidad).
Considere una tercera posibilidad, que es la inicialización de la copia, pero la conversión es explícita:
Y y = Y(x);
o
Y y = (Y)x;