web-dev-qa-db-fra.com

Que fait un deux-points après un nom de constructeur C ++?

Que fait l'opérateur deux points (":") dans ce constructeur? Est-ce équivalent à MyClass(m_classID = -1, m_userdata = 0);?

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};
82
spencewah

Il s'agit d'un liste d'initialisation, et fait partie de l'implémentation du constructeur.

La signature du constructeur est:

MyClass();

Cela signifie que le constructeur peut être appelé sans paramètres. Cela en fait un constructeur par défaut , c'est-à-dire un constructeur qui sera appelé par défaut lorsque vous écrivez MyClass someObject;.

La partie : m_classID(-1), m_userdata(0) est appelée liste d'initialisation. C'est un moyen d'initialiser certains champs de votre objet (tous, si vous le souhaitez) avec les valeurs de votre choix, au lieu de les laisser comme non définis.

Après avoir exécuté la liste d'initialisation, le corps du constructeur (qui se trouve être vide dans votre exemple) est exécuté. À l'intérieur, vous pouvez faire plus d'affectations, mais une fois que vous l'avez entré, tous les champs ont déjà été initialisés - soit sur des valeurs aléatoires non spécifiées, soit sur celles que vous avez choisies dans votre liste d'initialisation. Cela signifie que les affectations que vous effectuez dans le corps du constructeur ne seront pas des initialisations, mais des changements de valeurs.

91
Daniel Daranas

Il s'agit d'une liste d'initialisation.

Au moment où vous entrez dans le corps du constructeur, tous les champs ont déjà été construits; s'ils ont des constructeurs par défaut, ceux-ci ont déjà été appelés. Maintenant, si vous leur attribuez une valeur dans le corps du constructeur, vous appelez l'opérateur d'affectation de copie, ce qui peut signifier libérer et réacquérir des ressources (par exemple de la mémoire) si l'objet en possède.

Donc, dans le cas de types primitifs comme int, il n'y a aucun avantage par rapport à leur assignation dans le corps du constructeur. Dans le cas d'objets ayant un constructeur, il s'agit d'une optimisation des performances car elle évite de passer par deux initialisations d'objet au lieu d'une.

Une liste d'initialisation est nécessaire si l'un des champs est une référence car une référence ne peut jamais être nulle, pas même dans le bref laps de temps entre la construction de l'objet et le corps du constructeur. Ce qui suit génère l'erreur C2758: 'MyClass :: member_': doit être initialisé dans la liste des initialiseurs de base/membre du constructeur

class MyClass {
public :
    MyClass(std::string& arg) {
        member_ = arg;
    }
    std::string& member_;
};

La seule manière correcte est:

class MyClass {
public :
    MyClass(std::string& arg) 
        : member_(arg) 
    {
    }
    std::string& member_;
};
43
Asik

Il indique le début d'une liste d'initialisation, qui sert à initialiser les variables membres de votre objet.

Quant à: MyClass(m_classID = -1, m_userdata = 0);

Cela déclare un constructeur qui peut prendre des arguments (afin que je puisse créer un MyClass en utilisant MyClass m = MyClass(3, 4), ce qui entraînerait m_classID étant 3 et m_userdata étant 4). Si je ne passais aucun argument au constructeur MyClass, cela entraînerait la création d'un objet équivalent à la version avec la liste d'initialisation.

2
Dominic Rodger

Il signale le début d'une liste d'initialisation.

De plus, il n'est pas équivalent à MyClass (m_classId = -1, m_userData = 0). Ceci tente de définir un constructeur avec 2 paramètres qui ont des valeurs par défaut. Cependant, les valeurs manquent de types et ne doivent pas du tout être compilées.

2
JaredPar

C'est un liste d'initialisation . Dans votre exemple, c'est plutôt quelque chose comme ça (quelque chose comme ça - ne veut pas dire que c'est équivalent dans tous les cas):


class MyClass {

public:

    MyClass(){
         m_classID = -1;
         m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;

};
1
Marcin Deptuła

Cela s'appelle liste d'initialisation des membres. Il est utilisé pour appeler les constructeurs de superclasse et donner à vos variables membres une valeur initiale au moment de leur création.

Dans ce cas, il initialise m_classID à -1 et m_userData à NULL.

Ce n'est pas tout à fait équivalent à assigner dans le corps du constructeur, car ce dernier crée d'abord les variables membres, puis les assigne. Avec l'initialisation, la valeur initiale est fournie au moment de la création, donc dans le cas d'objets complexes, elle peut être plus efficace.

1
JohnMcG

Ce n'est pas précisément un opérateur. Cela fait partie de la syntaxe d'un constructeur.

Ce que cela veut dire, c'est que la liste des variables membres et leurs valeurs initiales seront suivies.

Les membres constants doivent être initialisés de cette façon. Les non constantes peuvent également être initialisées ici, tant qu'elles peuvent être effectuées avec une seule expression. S'il faut plus de code que cela pour initialiser un membre, vous devez mettre du code réel entre les {} pour le faire.

Beaucoup de gens aiment mettre à peu près tout leur code constructeur dans la liste des initiateurs. J'ai un collègue qui écrit régulièrement des cours avec plusieurs écrans d'initiateurs, puis met "{}" pour le code constructeur.

1
T.E.D.

C'est le début d'une liste d'initialisation qui définit les variables membres lors de la construction de l'objet. Votre exemple "MyClass (m_classID = -1, m_userdata = 0);" n'est pas possible car vous n'avez pas défini le constructeur correct et vous ne pourrez pas accéder aux variables membres dans la liste des paramètres de toute façon ... vous pourriez avoir quelque chose comme:

MyClass( int classId = -1, void* userData = 0 ) : m_classID(classId), m_userdata(userData) {}

La liste d'initialisation est considérée comme meilleure que:

MyClass( int classId = -1, void* userData = 0 ) {
    m_classID = classId;
    m_userdata = userData;
}

Google pour plus d'informations.

1
Patrick

Dans ce cas: Oui, ist est équivalent car seuls les types primitifs sont concernés.

Si les membres sont des classes (structures), vous devriez préférer la liste d'initialisation. En effet, sinon, les objets sont construits par défaut puis attribués.

0
SebastianK