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

C++ Discussion :

problème avec mon constructeur


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut problème avec mon constructeur
    Bonjour, j'ai une classe que voici :

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    class Classe
    {
      private :
     
        int _num; /* numero de la classe */
    	int _aine, _benj;
    	int _eff; /* effectif de la classe : somme des effectifs des classes ainee et benjamin */
    	double _ward; /* critere de ward */
    	double _ind; /* indice d'agregation */
     
      public :
     
    	  /* constructeur par defaut */
    	  Classe();
     
    	  /* constructeurs */
    	  Classe(int num);
    	  Classe(int num, double ward, double ind, const Classe & c1, const Classe & c2);
     
    	  /* destructeur */
    	  ~Classe() {};
     
    	  /* renvoie la valeur du critere de Ward */
    	  const double & getWard() {return _ward;};
     
    	  /* renvoie la valeur de l'indice d'agregation */
    	  const double & getIndice() {return _ind;};
     
    	  /* renvoie la valeur de l'effectif de la classe */
    	  const int getEffectif() {return _eff;};
     
    	  /* renvoie la valeur du numero de la classe */
    	  const int & getNum() {return _num;};
     
    };
    dont l'implementation est :

    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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    #include "Classe.h"
     
    /* constructeur par defaut */
    Classe::Classe()
    {
      _num = _aine = _benj = _eff = 0;
      _ward = _ind = 0.;
    }
     
    /* constructeurs */
    Classe::Classe(int num)
    {
      _num = _aine = _benj = num; _eff = 1;
      _ward = _ind = 0.;
    }
     
     
    Classe::Classe(int num, double ward, double ind, const Classe & c1, const Classe & c2)
    {
      int num1 = c1.getNum(), num2 = c2.getNum();
      _num = num; _ward = ward; _ind = ind; _eff = c1.getEffectif() + c2.getEffectif();
      if(num1 < num2)
      {
        _aine = num1; _benj = num2;
      }
      else /* num1 > num2 car par construction on sait que num1 != num2 */
      {
        _aine = num2; _benj = num1;
      }
    }
    Mon constructeur Classe::Classe(int num, double ward, double ind, const Classe & c1, const Classe & c2) a une erreur à la compilation :

    error C2662: 'Classe::getNum' : cannot convert 'this' pointer from 'const Classe' to 'Classe &'
    1> Conversion loses qualifiers
    je ne vois pas trop ce que je dois changer...

    Sinon, dans mon "Classe.h", que dois-je mettre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    1) double getWard() {return _ward;};
    2) const double getWard() {return _ward;};
    3) const double getWard() {return _ward;} const;
    4) const double & getWard() {return _ward;} const;
    Merci d'avance

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Re,

    OK, j'ai trouvé mon erreur. Mon bon code est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    	/* renvoie la valeur du critere de Ward */
    	const double getWard() const {return _ward;}
     
    	/* renvoie la valeur de l'indice d'agregation */
    	const double getIndice() const {return _ind;}
     
    	/* renvoie la valeur de l'effectif de la classe */
    	const int getEffectif() const {return _eff;}
     
    	/* renvoie la valeur du numero de la classe */
    	const int getNum() const {return _num;}

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Effectivement, bien que l'on puisse discuter 107 ans sur l'utilité de getters (je partage l'avis de certains que c'est souvent inutile et que cela viole régulièrement demeter), si tu en place un, il faut veiller:
    • à ce que la fonction soit constante (pour pouvoir l'appeler depuis des objets constants)
    • à ne jamais renvoyer une référence non constante vers le membre (ce qui te ferait perdre tout l'intérêt de l'encapsulation)
    De plus, lorsqu'il s'agit de renvoyer un type primitif (int, double, ...), l'intérêt de le renvoyer par référence est réduit à presque rien car ce n'est pas la copie de ce genre de données qui prend réellement du temps ou qui peut poser problème.

    Enfin, on peut réellement se poser la question de l'intérêt de les renvoyer sous forme constante, etant donné qu'il ne s'agit pas d'une référence mais d'une copie de l'objet, et que de ce fait la modification de la variable qui la reçoit, si elle est effectivement illogique, n'aura aucun impact sur l'objet lui-même

    Par contre, tu devrais envisager d'utiliser plutôt les listes d'initialisations, même pour les types primitifs

    Il existe en effet des pseudo constructeurs pour les types primitifs, et, de manière générale, c'est une bonne habitude à prendre car, pour des classes plus complexes, l'affectation dans le constructeur peut avoir des conséquences gourmandes en temps et en mémoire.

    Ainsi, le constructeur par défaut de ta classe pourrait très bien être proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Classe::Classe():_num(0),_ain(0),
                    _benj(0),_eff(0),
                    _ward(0.0),_ind(0.0)
    {
    }
    (idem pour les autre)

    Pour terminer sur le détail qui concerne uniquement la visibilité du code, je te conseillerais très franchement de veiller à ce qu'il n'y ait qu'une instruction par ligne (voire, si une instruction est réellement trop longue, une instruction sur plusieurs ligne), et donc d'éviter les codes proches de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _num = _aine = _benj = _eff = 0;
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _num = num; _ward = ward; _ind = ind; _eff = c1.getEffectif() + c2.getEffectif();
    Le premier n'est en effet qu'un "sucre syntaxique" datant du temps où les compilateurs avaient vraiment besoin d'être aidés dans leurs optimisations, et n'est actuellement pas plus efficace que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    _num =0;
    _aine = 0;
    _benj = 0;
    _eff = 0;
    le second revient strictement à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    _num = num; 
    _ward = ward; 
    _ind = ind; 
    _eff = c1.getEffectif() + c2.getEffectif();
    avec, chaque fois, la lisibilité du code en moins
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Merci koala01 pour tes conseils.

    Concernant les getters, tout comme toi, je trouve que c'est "plus compliqué" que de faire un "simple" maclasse.monchamp plutôt que maclasse.getMonChamp();

    Mais dans ce cas, cela veut dire que tout le private devient public ou y a-t-il qqch qui m'échappe ?

    Je viens du C, et si je ne me suis pas mis au C++ depuis longtemps, c'est uniquement à cause des getters et setter. Mais c'est en programmant en C++ que je découvrirais les joies (et facilités) de ce langage

    Merci

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par salseropom Voir le message
    Merci koala01 pour tes conseils.

    Concernant les getters, tout comme toi, je trouve que c'est "plus compliqué" que de faire un "simple" maclasse.monchamp plutôt que maclasse.getMonChamp();

    Mais dans ce cas, cela veut dire que tout le private devient public ou y a-t-il qqch qui m'échappe ?
    Il y a en fait quelque chose qui t'échappe, parce que ce n'est absolument pas ce que je voulais dire.

    Il y a un principe que l'on peut aborder sous le nom de "la règle de la connaissance minimale", qui a été énoncé pour la première fois par un certain demeter (d'où le nom réel de "loi de demeter) qui dit qu'une classe ne doit exposer que ce qui est réellement nécessaire.

    Pour être précis, elle dit que si un objet A utilise un objet B qui, lui même utilise un objet C, l'objet A n'a aucun besoin de connaitre l'objet C.

    L'idée générale est de penser plus en terme de "services" qu'une classe peut / doit rendre (ou en terme de messages qu'elle peut recevoir auxquels elle peut répondre) qu'en terme des données.

    Par exemple, lorsque tu veut modéliser une voiture, les message qu'elle peut recevoir, c'est "demarrerMoteur", "tournerGauche","tournerDroite","accelerer", "Arreter","ArreterMoteur", ...

    Elle peut répondre à quelque messages qui la questionnent comme "vitesse", "regimeMoteur" ou "niveauReservoir".

    Les membres de la classe "Voiture" qui permettent à la classe de réagir correctement à chaque message n'ont pour la plupart aucune raison d'être accessible depuis "l'extérieur" de la classe voiture.

    Bien sur, dans l'exemple présent, il y aura sans doute un membre qui représente le régime moteur, qui sera "exposé" par la réponse fournie par "regimeMoteur".

    Mais la vitesse sera sans doute évaluée sur base du régime moteur multiplié par 60 (un régime moteur est généralement calculé en tours / minutes-1), par le rapport correspondant à la vitesse engagée et par le périmètre du train roulant divisé par le facteur qui permet de transformer l'unité utilisée pour le périmètre du train roulant en km.

    De même, le niveau du réservoir sera normalement le quotient entre la capacité du réservoir et la quantité de carburant actuelle.

    La manière dont les différentes données (capacité du réservoir, périmètre du train roulant, régime moteur, vitesse engagée, quantité de carburant actuelle, j'en passe et de meilleures) sont représentées dans la classe n'a, en définitive, aucune espèce d'importance et entre dans la catégorie du "détail d'implémentation": ces données sont uniquement là pour que ta classe Voiture soit en mesure de rendre les services que l'on attend d'elle.

    D'ailleurs, il est plus que vraisemblable que tu aies en fait une classe réservoir qui présente elle-même une interface permettant de gérer la capacité du réservoir, la quantité d'essence contenue, le fait de rajouter ou de retirer du carburant (jusqu'à faire le plein ou tomber en panne d'essence) et qui sera utilisée en interne par la classe voiture

    Dans cet exemple l'utilisateur est l'objet A, la voiture est l'objet B, et le réservoir est l'objet C :

    En tant qu'utilisateur de la voiture, et parce que tu es doué du sens de la réflexion, tu sais qu'il y a un réservoir à la voiture, mais c'est un détail que tu n'a aucun besoin de connaitre et dont tu n'a aucun besoin de savoir comment il fonctionne réellement: tout ce dont tu as besoin, depuis la voiture, d'être en mesure de savoir quel est son niveau et d'être en mesure d'y rajouter du carburant
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Il y a un principe que l'on peut aborder sous le nom de "la règle de la connaissance minimale", qui a été énoncé pour la première fois par un certain demeter (d'où le nom réel de "loi de demeter) qui dit qu'une classe ne doit exposer que ce qui est réellement nécessaire.
    Heu ... C'est le nom d'un projet, en référence à la déesse de l'agriculture, où ce principe avait été formalisé.

    Mais effectivement, arrête de penser en termes de données comme tu devais faire en C, pense en termes de services rendus. Indice: le type FILE en C.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Réponses: 4
    Dernier message: 16/06/2011, 23h36
  2. Réponses: 5
    Dernier message: 04/04/2008, 00h14
  3. Problème avec mon service mysql et PhpMyAdmin
    Par Fixazo dans le forum Outils
    Réponses: 1
    Dernier message: 28/08/2005, 18h02
  4. problème avec mon lecteur CD
    Par leo13 dans le forum Périphériques
    Réponses: 3
    Dernier message: 16/08/2005, 11h21
  5. Problème avec mon firewall ...
    Par Wis dans le forum Tomcat et TomEE
    Réponses: 15
    Dernier message: 06/04/2004, 08h46

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