IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

constructeur et paramètre par référence constante


Sujet :

Langage C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut constructeur et paramètre par référence constante
    Bonjour,

    décidemment, 2 ans de C# et je n'y comprend plus rien au c++

    Prenons le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    struct Foo
    {
    	Foo( const std::string & str ) { cout << str << endl; }
    };
     
    void f( const std::string & str )
    {
    	cout << str << endl;
    }
     
    int main()
    {
    	f( "test" ); // ok
    	Foo( "test" ); //ok
    	std::string test= "test";
    	f( test ); //ok
    	Foo( test ); // erreur
    }
    Pourquoi est-ce que la dernière ligne ne compile pas?
    En plus mon compilateur (VS 2010) est complètement perdu, l'erreur qu'il me donne est sans rapport:
    error C2371: 'test' : redefinition; different basic types
    il croit que j'essaie de redéfinir la variable test.

    Sauriez-vous me dire pourquoi cette dernière ligne ne compile pas?

    Il me semblait que le cast en référence constante était automatique.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    parce qu'il n'existe pas de fonction Foo qui prend un const std::string& en pramètres.

    Foo est un constructeur et la syntaxe est
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Mais pourtant fonctionne
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Il me semble que cette écriture en fait déclare une variable locale "test" de type Foo, exactement comme si l'on avait écrit Foo test; Les parenthèses sont ignorées.
    De la même manière on peut déclarer double (d); au lieu de double d; même si ça ne sert pas à grand chose à part embrouiller le lecteur.

    Ce n'est pas si embêtant qu'il n'y parait vu qu'en pratique on ne va jamais appeler un constructeur directement et créer un objet temporaire mais plutôt écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Foo g(test);
    Foo h = Foo(test);
    Et dans ce cas tout se passe comme prévu.

    Edit :
    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct Fun
    {
       Fun(){std::cout << "ctor\n";}
       Fun(int i){std::cout << "ctor int\n";}
       void toto(){std::cout << "toto\n";}
    };
     
    int main()
    {
       Fun(4); // construit un Fun temporaire avec ctor(int)
       Fun (f); // construit une variable f de type Fun (ctor par défaut);
       f.toto();
    }
    affiche :
    ctor int
    ctor
    toto

    Faut avouer que Les designers du C# en partant de zéro ont eu l'avantage de pouvoir éviter ce genre d’ambiguïté dans la grammaire héritée du C

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Ce n'est pas si embêtant qu'il n'y parait vu qu'en pratique on ne va jamais appeler un constructeur directement
    Et bien, ahem... c'est ce que je comptais faire pour mon logger.
    L'idée c'est que j'ai mon logger en singleton (ou variable globale c'est pareil), et je comptais faire une fonction libre dans le style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void my_log( mon_looger.instance()->Log( "blabla" );
    Sauf qu'en fait, je trouvais pas mal l'idée de, à la place de cette fonction, faire une classe Log qui serait amie de mon logger, afin de tout mettre en privé dans mon logger et ainsi d'en d'interdire totalement l'utilisation.

    Et j'en suis donc arrivé à une classe Log dont le constructeur prend un const string & en paramètre et c'est ce constructeur qui effectue le log. Et ça marchait très bien jusqu'à aujourd'hui où j'ai essayé de logger un objet string (jusqu'ici je ne loggais que des chaines du type "blabla" ).
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  6. #6
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    A noter également que, en utilisant l'exemple du premier post, le code suivant fonctionne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    string test = "test";
    Foo( test.c_str() );
    et c'est bien le constructeur Foo( const string & ) qui est appelé.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  7. #7
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    La syntaxe d'une déclaration c'est :
    Où T est "presque" (*) le type et les Dn des "déclarateurs". Et il se trouve que si un Dn à la forme :
    Alors les parenthèses ne servent "à rien".

    En effet dans certains cas la syntaxe :
    A l'effet que tu attends, mais il ne faut pas oublier que le C++ a une grammaire qui est évaluée en fonction du contexte. Et la grammaire des déclarations semble prioritaire sur celle des expressions (ce qui n'est pas illogique étant donné que la grammaire des expressions régit un fonctionnement "plus fin" que celle des déclarations).

    Ca c'était la partie "grammaire", maintenant il y a quelque chose qui me gène dans le fait que tu voudrais que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Foo(test); //Tout seul, sans rien autour
    Ai un impact sur le code.

    Le C++ n'est pas un langage pure, mais là c'est quand même un effet de bord un peu fort. Sans compter que les objets temporaires (donc les appels aux constructeurs/destructeurs) sont un point sur lequel les compilateurs optimisent, y introduire des effets de bord nécessaires c'est courir au devant de problèmes incompréhensibles.

    Pour revenir à ton problème, mets les parenthèses autour de Foo et pas de test, tu auras le comportement que tu veux (c'est une notation de cast, mais si ton constructeur n'est pas explicite, ça aura bien le comportement voulu : construire un Foo depuis un string). Sauf si ça optimise encore une fois.

    (*) Dans int * i; T est int et D *i, d'où mon "presque", idem pour la référence et d'autre élément dans le cas d'autre déclaration.

Discussions similaires

  1. Réponses: 2
    Dernier message: 23/11/2012, 17h39
  2. Passage de Paramètre par référence constructeur
    Par malus56 dans le forum Débuter
    Réponses: 3
    Dernier message: 11/07/2011, 11h10
  3. [EJB] Passage des paramètres par référence
    Par salome dans le forum Java EE
    Réponses: 2
    Dernier message: 05/07/2005, 12h25
  4. Réponses: 10
    Dernier message: 03/03/2005, 14h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo