2009-08-06 11 views
4

J'ai un code à Image.cpp:C++ question de déclaration de méthode

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

and in Image.h: 
class Image: public DrawAble, public RenderAble 
{ 
... 
private : 
    std::string *m_sFileName; 
}; 

Ma question est: ce qui se passe avec m_sFilename dans la première ligne? Je suppose qu'il est défini sur NULL mais à quoi cela sert-il? Serait-ce la même chose à faire:

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

Répondre

0

Ce serait la même chose que faire

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

S'il vous plaît noter que l'utilisation d'un pointeur vers un std::string est généralement pas une bonne idée, comme une chaîne vide est un tout aussi bon marqueur rien et vous ne devez pas vous soucier de la destruction si vous en faites un membre normal.

+0

Ce n'est pas exactement la même chose car si vous faites ce dernier, vous ne pouvez pas créer une image const. Probablement pas quelque chose que vous voulez faire dans ce cas, mais potentiellement intéressant pour les types plus légers. –

+0

Si vous avez une image const, vous voudrez probablement aussi un const m_sFileName, donc je ne vois pas le problème. – MSalters

0
m_sFileName(0) 

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

m_sFileName = 0; 

Cependant, l'initialisation recommandée est 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.

0

Il fait la même chose que:

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

Vous êtes rapides ... – Lucas

11

La première utilise ce qu'on appelle un initialization list. Lorsque vous entrez le corps du constructeur, tous les membres de classes doivent avoir été construits (pour pouvoir être utilisés). Donc, si vous avez ceci:

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

Ainsi, str obtient construit, puis affecté. Mieux aurait été:

class Foo 
{ 
public: 
    Foo() 
    : str("String.") 
    { 
    } 
private: 
    std::string str; 
}; 

Alors que str est directement construit. Cela ne fait pas de 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 par rapport au code courant dans le constructeur. La liste d'initialisation doit être utilisée pour l'initialisation, le constructeur doit être utilisé pour exécuter le code.

De même, pourquoi utiliser un pointeur sur une chaîne? 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 de initialiseur:

listes Initializer ont plus d'utilisations que de membres de la initialisation classe.Ils peuvent être utilisés pour passer des arguments dans les 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 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; 
}; 
+2

Voilà une bonne réponse! Sachez également que parfois les listes d'initialisation sont la seule façon de le faire car les variables et références de const ne peuvent pas être assignées ... dans ce cas, vous devez utiliser des listes d'initialisation. –

+0

Heh, vous avez tapé le commentaire pendant que j'ai édité. :) – GManNickG

+0

Bonne réponse. Avec beaucoup plus de détails que ce que j'avais espéré! Je suppose que le mot qui manquait dans mon vocabulaire était "listes d'initialisation". Alors maintenant je sais. Merci! –

2

Ceci est appelé 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 paramètres. Dans ces cas, vous n'avez pas d'autre choix que d'utiliser un initialiseur.

0

La syntaxe que vous utilisez:

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

est appelée une liste d'initialisation. Il affectera la valeur 0 à votre variable membre.

Utilisation de m_sFileName = 0; dans le corps du constructeur 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).

0

Ces deux variantes sont presque même - vous avez raison que le

: m_sFileName(0) 

est à l'origine m_sFileName être initialisés à 0.

La raison pour laquelle C++ possède cette syntaxe d'initialisation spéciale devient importante lorsque vous souhaitez créer un const Image. (Probablement pas quelque chose que vous voulez faire dans ce cas, mais cela peut être quelque chose que vous voudrez faire pour les types "légers".) Pour un const Image, this est un pointeur const dans le constructeur ainsi que dans chaque fonction membre "normale" , 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 et non l'affectation. Incidemment, si m_sFileName était un objet, il y aurait une différence supplémentaire en plus des considérations const: La liste d'initialisation provoquerait l'appel 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 - pour signifier que vous êtes en train d'initialiser, pas d'assigner.