O C ++ possui um recurso (não consigo descobrir o nome apropriado), que chama automaticamente os construtores correspondentes dos tipos de parâmetros se os tipos de argumento não forem os esperados.
Um exemplo muito básico disso é chamar uma função que espera a std::string
com um const char*
argumento. O compilador irá gerar código automaticamente para chamar o std::string
construtor apropriado .
Gostaria de saber, é tão ruim para a legibilidade como eu acho que é?
Aqui está um exemplo:
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);
Tudo bem? Ou vai longe demais? Se não devo fazê-lo, posso de alguma forma fazer Clang ou GCC avisar sobre isso?
Respostas:
Isso é chamado de construtor de conversão (ou construtor implícito ou conversão implícita).
Não conheço uma opção em tempo de compilação para avisar quando isso ocorre, mas é muito fácil evitar isso; basta usar a
explicit
palavra - chaveSe a conversão ou não de construtores é uma boa ideia: depende.
Circunstâncias em que a conversão implícita faz sentido:
std::string
refletir o mesmo conceito do qualconst char *
ele pode implicitamente converter); portanto, a conversão implícita faz sentido.Circunstâncias em que a conversão implícita faz menos sentido:
AnsiString
classe não deve implicitamente construir a partir de aUnicodeString
, pois a conversão Unicode em ANSI pode perder informações.Leitura adicional:
fonte
Isso é mais um comentário do que uma resposta, mas grande demais para ser colocado em um comentário.
Curiosamente,
g++
não me deixa fazer isso:Produz o seguinte:
No entanto, se eu alterar a linha para:
Ele realizará essa conversão.
fonte
gcc
opções do compilador (que parece não haver nenhuma para resolver esse caso em particular). Eu não olhei muito a fundo (eu deveria estar trabalhando :-), mas dadagcc
a aderência ao padrão e o uso daexplicit
palavra-chave uma opção de compilador provavelmente foi considerada desnecessária.Texture
provavelmente não deve ser construído implicitamente (de acordo com as diretrizes em outras respostas); portanto, seria um site de chamada melhorrenderer.Draw(Texture("foo.png"));
(supondo que funcione conforme o esperado).É chamado de conversão implícita de tipo. Em geral, é uma coisa boa, pois inibe repetições desnecessárias. Por exemplo, você obtém automaticamente uma
std::string
versãoDraw
sem precisar escrever nenhum código extra. Também pode ajudar a seguir o princípio de aberto-fechado, pois permite expandirRenderer
os recursos do mesmo sem se modificarRenderer
.Por outro lado, não é sem inconvenientes. Pode dificultar descobrir de onde vem um argumento, por um lado. Às vezes, pode produzir resultados inesperados em outros casos. É para isso que
explicit
serve a palavra-chave. Se você o colocar noTexture
construtor, desabilitará o uso desse construtor para conversão implícita de tipo. Não conheço um método para alertar globalmente sobre a conversão implícita de tipo, mas isso não significa que não exista um método, apenas que o gcc tem um número incompreensivelmente grande de opções.fonte