Question de déclaration de méthode C ++

J’ai du code dans Image.cpp:

Image::Image( int width, int height, int depth ) : m_sFileName(0) { ... } and in Image.h: class Image: public DrawAble, public RenderAble { ... private : std::ssortingng *m_sFileName; }; 

Ma question est la suivante: que se passe-t-il avec m_sFilename en première ligne? Je suppose qu’il est défini sur NULL, mais quel est l’intérêt de le faire de cette façon. Serait-ce la même chose à faire:

 Image::Image( int width, int height, int depth ) { m_sFileName(0); ... } 

Le premier utilise ce qu’on appelle une liste d’initialisation .

Lorsque vous entrez dans le corps du constructeur, toutes les classes membres doivent avoir été construites (pour pouvoir être utilisées). Donc si vous avez ceci:

 class Foo { public: Foo() : str() // this is implicit { str = "Ssortingng."; } private: std::ssortingng str; }; 

Donc, str est construit, puis assigné. Mieux aurait été:

 class Foo { public: Foo() : str("Ssortingng.") { } private: std::ssortingng str; }; 

Donc, str se construit directement. Cela ne fait aucune différence dans votre cas car les pointeurs n’ont pas de constructeur.

Il est généralement considéré comme une bonne pratique d’utiliser une liste d’initialisation sur le code en cours d’exécution dans le constructeur. La liste d’initialisation doit être utilisée pour l’ initialisation , le constructeur doit être utilisé pour le code en cours d’exécution.

Aussi, pourquoi utiliser un pointeur sur ssortingng? Si vous voulez une chaîne, utilisez une chaîne; pas un pointeur sur une chaîne. Les chances sont, vous voulez réellement une chaîne.


En savoir plus sur les listes d’initialisation:

Les listes d’initialisation ont plus d’utilisations que simplement initialiser des membres de la classe. Ils peuvent être utilisés pour passer des arguments aux constructeurs de base:

 class Foo { public: Foo(int i) { /* ... */ } } class Bar : public Foo { public: Bar() : Foo(2) // pass 2 into Foo's constructor. // There is no other way of doing this. { /* ... */ } }; 

Ou membres constants:

 class Foo { public: Foo() : pi(3.1415f) { pi = 3.1415f; // will not work, pi is const. } private: const float pi; }; 

Ou des références:

 class Foo { public: Foo(int& i) : intRef(i) // intRef refers to the i passed into this constructor { intRef = i; // does *not* set intRef to refer to i! // rather, it sets i as the value of // the int intRef refers to. } private: int &intRef; }; 

Ceci s’appelle un initialiseur. Vous devriez vous habituer à les utiliser. Dans ce cas, cela n’a pas d’importance. Mais dans d’autres cas, ne pas les utiliser pourrait signifier une double initialisation d’un membre non pointeur. D’abord avec les valeurs par défaut, puis avec vos valeurs. Et enfin, il y a le cas d’un membre sans constructeur sans parameters. Dans ces cas, vous n’avez pas d’autre choix que d’utiliser un initialiseur.

Ce serait la même chose que de faire

 Image::Image( int width, int height, int depth ) { m_sFileName = 0; // ... } 

Veuillez noter que l’utilisation d’un pointeur sur std::ssortingng n’est généralement pas une bonne idée, car une chaîne vide est un bon marqueur Nothing-here-marqueur et vous n’avez pas à vous soucier de la destruction si vous en faites un membre normal.

 m_sFileName(0) 

dans le corps du constructeur sera interprété comme appelant une fonction avec le nom m_sFileName. Vous pouvez le remplacer par

 m_sFileName = 0; 

Cependant, l’initialisation recommandée se trouve dans la liste d’initialisation du constructeur, comme dans le premier exemple. Tout membre de données qui n’est pas initialisé dans la liste d’initialisation du constructeur sera automatiquement initialisé avec le constructeur par défaut de son type.

Il fait la même chose que:

 Image::Image( int width, int height, int depth ) { m_sFileName = 0; ... } 

La syntaxe que vous utilisez:

 Image::Image( int width, int height, int depth ) : m_sFileName(0) { ... } 

s’appelle une liste d’initialisation. Il assignera la valeur 0 à votre variable membre.

Using m_sfileName = 0; dans le constructeur, le système serait moins performant car le membre serait initialisé deux fois (une fois automatiquement car il n’est pas inclus dans la liste d’initialisation et une seconde fois avec votre initialisation explicite).

Ces deux variantes sont presque les mêmes – vous avez raison de dire que le

 : m_sFileName(0) 

provoque l’ m_sFileName de m_sFileName à 0 .

La raison pour laquelle C ++ a cette syntaxe d’initialisation spéciale devient importante lorsque vous souhaitez créer une const Image . (Ce n’est probablement pas quelque chose que vous voulez faire dans ce cas, mais cela peut l’être pour les types “légers”.) Pour une const Image , this s’agit d’un pointeur const dans le constructeur ainsi que dans chaque membre “normal” fonction, et donc m_sFileName=0 n’est pas autorisé.

Pour résoudre ce problème, C ++ a des listes d’initialisation, qui effectuent l’initialisation, pas l’atsortingbution. Incidemment, si m_sFileName était un object, il y aurait une différence supplémentaire en plus des considérations de const : la liste d’initialisation provoquerait l’ m_sFileName du constructeur de m_sFileName , alors que l’affectation appellerait l’opérateur d’affectation.

En dehors de toutes ces considérations, les listes d’initialisation sont un bon moyen de communiquer l’intention – de signifier que vous initialisez, et non n’assignez.