Je travaille en c ++ depuis un certain temps maintenant, mais je ne suis pas sûr de la différence entre
public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}
et
public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}
J'ai l'impression qu'ils font la même chose, mais y a-t-il une différence pratique entre ces 2 syntaxes. Est-ce que l'un d'entre eux est plus sûr que l'autre et gère-t-il les paramètres par défaut différemment?.
Pas totalement habitué au premier exemple, donc si je me suis trompé, je m'en excuse.
Ce ne sont pas les mêmes si member1
et member2
sont non-POD (c'est-à-dire non - [~ # ~] p [~ # ~] lain O ld D ata ) les types:
public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}
est équivalent à
public : Thing(int _foo, int _bar) : member1(), member2(){
member1 = _foo;
member2 = _bar;
}
car ils seront initialisés avant que le corps du constructeur ne commence à s'exécuter, donc en gros, le travail est effectué deux fois. Cela signifie également que si le type de ces membres n'a pas de constructeur par défaut, alors votre code compilera not.
La première est la meilleure pratique recommandée, car elle est plus idiomatique et évite de réinitialiser les champs pour les types qui ont un constructeur par défaut (c'est-à-dire les types non primitifs).
Lorsque vous initialisez uniquement un membre à l'intérieur du corps du constructeur, le compilateur génère une instruction d'initialisation de membre par défaut si vous le pouvez, vous finissez donc par l'initialiser doublement. Cela peut ne pas être un gros problème dans certains cas, mais peut être un sérieux problème de performances si la construction de l'objet est coûteuse.
Cependant, les types définis par l'utilisateur sans constructeur par défaut (n explicitement défini ou généré) ne peuvent pas être initialisés de cette façon, donc une erreur de compilation est produite. Il en va de même pour les champs const et reference - ceux-ci ne peuvent être initialisés explicitement que dans la liste d'initialisation des membres.
La seule chose à ajouter à Péter Török réponse est que la liste d'initialisation est le seul moyen d'initialiser les membres const d'objets, à savoir:
class foo
{
public:
foo(int value)
: myConstValue(value)
{};
foo()
{
myConstValue = 0; // <=== Error! myConstValue is const (RValue), you can't assign!
};
private:
const int myConstValue;
}
Dans votre exemple de code, le premier dans l'initialisation du constructeur et le second est l'affectation à l'intérieur du corps du constructeur.
La liste d'initialisation du constructeur est le meilleur moyen de faire l'initialisation de tous les membres car elle améliore les performances.
class A
{
string name;
public:
A(string myname):name(myname) {}
}
Dans le cas ci-dessus, le compilateur ne créera pas d'objet temporaire pour effectuer l'initialisation. Cependant dans le cas suivant:
A::A()
{
name = myname;
}
Un objet temporaire distinct est créé et cet objet temporaire est transmis à l'opérateur d'affectation de string
pour être affecté à name
. Ensuite, l'objet temporaire est détruit, ce qui n'est pas très efficace.
Remarque: Il est obligatoire qu'une référence ou un membre const soit initialisé dans une liste d'initialisation de constructeur. Ils ne peuvent pas être "attribués" dans le corps du constructeur.
Outre les autres réponses, je voudrais mentionner que l'initialisation du constructeur uniquement pour initialiser les variables membres.
class Demo
{
int a;
int b;
public:
Demo(int a,int b):a(a),b(b)
{
}
};
si nous initialisons a et b à l'intérieur du constructeur, ce serait une auto-affectation.
La première est l'initialisation, en utilisant une liste d'initialisation et la seconde est la construction par défaut puis l'affectation. Le premier est au moins aussi rapide que le second et est préférable au second.