C ++ tiene una característica (no puedo encontrar el nombre propio), que llama automáticamente a los constructores coincidentes de los tipos de parámetros si los tipos de argumento no son los esperados.
Un ejemplo muy básico de esto es llamar a una función que espera a std::string
con un const char*
argumento. El compilador generará automáticamente código para invocar al std::string
constructor apropiado .
Me pregunto, ¿es tan malo para la legibilidad como creo que es?
Aquí hay un ejemplo:
class Texture {
public:
Texture(const std::string& imageFile);
};
class Renderer {
public:
void Draw(const Texture& texture);
};
Renderer renderer;
std::string path = "foo.png";
renderer.Draw(path);
¿Eso está bien? ¿O va demasiado lejos? Si no debería hacerlo, ¿puedo hacer que Clang o GCC lo adviertan de alguna manera?
Respuestas:
Esto se conoce como un constructor de conversión (o, a veces, constructor implícito o conversión implícita).
No conozco un cambio de tiempo de compilación para advertir cuando esto ocurre, pero es muy fácil de prevenir; solo usa la
explicit
palabra clave.En cuanto a si los constructores de conversión son o no una buena idea: depende.
Circunstancias en las que la conversión implícita tiene sentido:
std::string
reflejar el mismo concepto del queconst char *
se puede convertir implícitamente), por lo que la conversión implícita tiene sentido.Circunstancias en las que la conversión implícita tiene menos sentido:
AnsiString
clase no debe construir implícitamente a partir de aUnicodeString
, ya que la conversión de Unicode a ANSI puede perder información.Otras lecturas:
fuente
Esto es más un comentario que una respuesta, pero es demasiado grande para ponerlo en un comentario.
Curiosamente,
g++
no me deja hacer eso:Produce lo siguiente:
Sin embargo, si cambio la línea a:
Realizará esa conversión.
fuente
gcc
opciones del compilador (que no parece que haya ninguna para abordar este caso en particular). No busqué mucho más (se supone que debo estar trabajando :-), pero dadagcc
la adhesión al estándar y el uso de laexplicit
palabra clave, una opción de compilador probablemente se consideró innecesaria.Texture
probablemente no debería construirse implícitamente (de acuerdo con las pautas en otras respuestas), por lo que sería un mejor sitio de llamadarenderer.Draw(Texture("foo.png"));
(suponiendo que funcione como espero).Se llama conversión de tipo implícito. En general es algo bueno, ya que inhibe la repetición innecesaria. Por ejemplo, obtiene automáticamente una
std::string
versión deDraw
sin tener que escribir ningún código adicional para ello. También puede ayudar a seguir el principio abierto-cerrado, ya que le permite ampliarRenderer
las capacidades sin modificarseRenderer
.Por otro lado, no está exento de inconvenientes. Por un lado, puede dificultar averiguar de dónde proviene un argumento. A veces puede producir resultados inesperados en otros casos. Para eso está la
explicit
palabra clave. Si lo coloca en elTexture
constructor, deshabilita el uso de ese constructor para la conversión de tipo implícito. No conozco un método para advertir globalmente sobre la conversión de tipo implícita, pero eso no significa que no exista un método, solo que gcc tiene una cantidad incomprensiblemente grande de opciones.fuente