2010-12-10 4 views
0

envisager le code suivantquestion à obtenir la valeur de la classe

#include <iostream> 
using namespace std; 
class MyClass{ 
    int a; 
    public: 
    MyClass(int j) {a = j;} 
    int geta(void) {return a;} 
}; 

int main(void) 
{ 
    MyClass ob = 99;    

    cout << ob.geta(); 
} 

sortie de ce code est de 99 ma question est déclaration suivante ob MyClass est déclarer objet de classe MyClass et est autorisé ce genre de déclaration que l'objet est égale un certain nombre? déclaration peut-être plus spécifique serait MyClass ob (99) que pensez-vous?

Répondre

2

Lorsque vous créez un objet comme

MyClass ob =99 ; 

Vous appelez essentiellement constructeur de la classe.

est de même lorsque l'objet est créé comme

MyClass ob(99); 

Dans ce cas aussi, constructeur de classe est appelée.

+0

Non, il ne pas appeler constructeur de copie. Ajoutez 'MyClass (const MyClass & asdf): a (asdf.a) {cout <<" cc appel "<< endl;}' à son code. "cc appel" ne sera pas imprimé. – x13n

+0

@ x13n vous avez raison, si j'aime bien cet obj MyClass (99); MyClass ob = obj; alors le constructeur de la copie sera appelé – anand

+0

@ x13n: Vous avez tort et que @ Alien01 avait raison en premier lieu. Le langage spécifie que 'MyClass ob = 99' est équivalent à' MyClass ob (MyClass (99)) '. Autrement dit, le compilateur crée un temporaire avec le constructeur implicite et * puis * le copie dans l'objet réel. L'effet que vous voyez (manque de sortie de votre constructeur de copie) est dû à une optimisation, où le compilateur peut créer le temporaire au même endroit que l'objet résultant et donc élider la copie. Pour le vérifier, déclarez le constructeur de copie privé et vous obtiendrez une erreur d'accès dans le code. –

3

Vous avez fourni le constructeur en prenant un int. Sans explicit mot-clé, il peut être appelé implicitement - comme ici. Si vous écrivez MyClass ob(99), vous appellerez ce constructeur explicitement. Il n'y a aucune différence jusqu'à ce que vous déclariez le constructeur comme explicit. Vous obtiendrez une erreur de compilation en essayant d'assigner un int à un objet avec un constructeur explicite.

EDIT: J'ai vérifié - il utilise vraiment aussi le constructeur de copie, comme l'ont dit David et Alien01. C'est juste Visual Studio qui ne suit pas la norme.

+0

L'initialisation comme 'MyClass ob = 99;' signifie que le constructeur de copie doit être disponible (par exemple erreur s'il est privé), mais cela ne signifie pas que le constructeur de copie doit être appelé (peut être optimisé). – visitor

2

Ceci est la partie intéressante:

MyClass(int j) {a = j;} 

Par défaut, un constructeur avec un seul argument est implicite, ce qui signifie que le compilateur appelle automatiquement chaque fois que vous voulez attribuer un int où un MyClass devrait.

Si vous ne voulez pas ce comportement pour votre classe, modifiez simplement le constructeur à

explicit MyClass(int j) {a = j;} 

Et le comportement est parti, maintenant, vous devez explicitement (d'où le mot-clé) appeler le constructeur à chaque fois. Notez que le mot clé explicit ne doit apparaître que dans la déclaration du corps de la classe, mais pas dans une implémentation en dehors du corps.

P.S .: C'est, par exemple, comment const char* devient automatiquement un std::string lorsque ce dernier est attendu.

+1

+1 comme la réponse la plus claire jusqu'à présent. Il vaut la peine de souligner que la plupart des constructeurs à un seul argument doivent être déclarés explicites, car la conversion implicite est rarement (voire jamais) nécessaire et peut causer beaucoup de problèmes quand elle intervient. –

1

La réponse générale a déjà été fournie par d'autres, y compris @ x13n. Je vais essayer de fournir une explication un peu plus détaillée de ce que le code signifie vraiment.

La syntaxe MyObject ob = anotherMyObject; est équivalente à MyObject obj(anotherMyObject);. La signification est copie construire ob de l'objet anotherMyObject. Le compilateur correspondra toujours MyObject ob = ...; avec un appel au constructeur de copie (habituellement MyObject(MyObject const &), mais peut également être MyObject(MyObject&) si l'utilisateur le déclare comme tel).

Dans votre code, le côté droit n'est pas un MyObject, donc il ne peut pas être passé comme argument au constructeur de copie et le compilateur essayera de convertir ce rhs en quelque chose qui peut être utilisé avec le constructeur de copie de MyObject en appliquant les règles générales. Dans votre cas, il est un constructeur implicite qui prend un argument int, et qui peut être utilisé pour créer un MyObject temporaire, de sorte que le compilateur réécrit votre code pour être:

MyObject ob(MyObject(99)); 
//    ^^^ temporary created by the compiler to match the copy constructor 

Notez que ce n'est pas la même chose que MyObject ob(99), mais une combinaison des constructeurs int et de copie, même si l'effet global est similaire. Si le constructeur prenant un nombre entier a été déclaré explicit, le compilateur n'a pas pu l'utiliser pour fournir la conversion et le code échouerait à compiler.

Dans un commentaire à une autre réponse @ x13n indique qu'il ne s'agit pas d'un appel au constructeur de copie, comme si vous ajoutiez une trace à ce constructeur, la trace ne sera pas générée. C'est un problème complètement différent, où le compilateur est capable d'optimiser la copie en créant le temporaire dans exactement la même adresse que prend ob. Il y a deux façons de vérifier cela, toutes deux dépendant du fait que, bien que le compilateur puisse élider la copie, il doit respecter les mêmes restrictions. Nous pouvons donc MyObject ob(MyObject(99)) invalide de deux façons, soit désactiver l'accès au constructeur de copie ou de désactiver l'appel au constructeur avec un temporaire:

class test1 { 
    test1(test1 const &) {} // make the copy constructor private 
public: 
    test1(int) {} 
}; 
class test2 { 
public: 
    test2(test2 &) {} // make the copy constructor take a non-const reference 
         // i.e. disable the use of temporaries 
    test2(int) {} 
}; 
int main() { 
    test1 t1 = 99; // copy constructor is private in this context 
    test2 t2 = 99; // g++: no matching function call to test2::test2(test2) 
        // diagnostics will differ with other compilers 
} 
Questions connexes