C ++ a une fonctionnalité (je ne peux pas en trouver le nom correct), qui appelle automatiquement les constructeurs correspondants des types de paramètres si les types d'arguments ne sont pas ceux attendus.
Un exemple très basique de ceci appelle une fonction qui attend un std::string
avec un const char*
argument. Le compilateur générera automatiquement du code pour appeler le std::string
constructeur approprié .
Je me demande, est-ce aussi mauvais pour la lisibilité que je le pense?
Voici un exemple:
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);
C'est bien? Ou va-t-il trop loin? Si je ne devais pas le faire, puis-je faire en sorte que Clang ou GCC en avertisse?
Réponses:
Ceci est appelé constructeur de conversion (ou parfois constructeur implicite ou conversion implicite).
Je ne suis pas au courant d'un commutateur de compilation pour avertir lorsque cela se produit, mais c'est très facile à empêcher; utilisez simplement le
explicit
mot - clé.Quant à savoir si la conversion des constructeurs est une bonne idée: cela dépend.
Circonstances dans lesquelles la conversion implicite est logique:
std::string
refléter le même concept queconst char *
celui à partir duquel elles peuvent implicitement se convertir), donc la conversion implicite est logique.Circonstances dans lesquelles la conversion implicite est moins logique:
AnsiString
classe ne doit pas implicitement construire à partir de aUnicodeString
, car la conversion Unicode en ANSI peut perdre des informations.Lectures complémentaires:
la source
Il s'agit plus d'un commentaire que d'une réponse, mais trop gros pour mettre un commentaire.
Fait intéressant,
g++
ne me laisse pas faire cela:Produit les éléments suivants:
Cependant, si je change la ligne en:
Il effectuera cette conversion.
la source
gcc
options du compilateur (qui ne semblent pas exister pour résoudre ce cas particulier). Je n'y ai pas beaucoup approfondi (je suis censé travailler :-) mais étant donnégcc
l'adhésion à la norme et l'utilisation duexplicit
mot clé, une option de compilation a probablement été jugée inutile.Texture
ne devrait probablement pas être construit implicitement (selon les directives dans d'autres réponses), donc un meilleur site d'appel seraitrenderer.Draw(Texture("foo.png"));
(en supposant qu'il fonctionne comme je m'y attendais).C'est ce qu'on appelle la conversion de type implicite. En général, c'est une bonne chose, car elle empêche la répétition inutile. Par exemple, vous obtenez automatiquement une
std::string
version deDraw
sans avoir à écrire de code supplémentaire pour celle-ci. Il peut également aider à suivre le principe ouvert-fermé, car il vous permet d'étendreRenderer
les capacités de sans se modifierRenderer
.D'un autre côté, ce n'est pas sans inconvénients. Il peut être difficile de comprendre d'où vient un argument, d'une part. Il peut parfois produire des résultats inattendus dans d'autres cas. C'est à ça que
explicit
sert le mot-clé. Si vous le placez sur leTexture
constructeur, il désactive l'utilisation de ce constructeur pour la conversion de type implicite. Je ne suis pas au courant d'une méthode pour avertir globalement de la conversion de type implicite, mais cela ne signifie pas qu'une méthode n'existe pas, mais seulement que gcc a un nombre incompréhensiblement grand d'options.la source