Partage
  • Partager sur Facebook
  • Partager sur Twitter

Héritage et accès aux classes

Sujet résolu
    10 avril 2008 à 13:58:26

    Bonjour,

    Le problème porte sur l'héritage en C++. Nous avons un classe mère nommée Contenu et une classe fille nommée Animal et Environnement.

    Nous déclarons un tableau tab de Contenu que nous remplissons d'objets de type Animal et Environnement

    La question est, à partir de tab[i], comment peut-on accéder aux méthodes des classes filles?

    Merci d'avance.
    • Partager sur Facebook
    • Partager sur Twitter
      10 avril 2008 à 15:07:46

      Ta classe Contenu est-elle une classe abstraite ? Ton tableau tab st-il un tableau de pointeur sur des objets Contenu ?
      • Partager sur Facebook
      • Partager sur Twitter
        10 avril 2008 à 15:30:04

        Soit par down-casting avec dynamic_cast<>. Mais ce n'est pas très propre. Tu dois définir un moyen pour désigner que ton objet est en fait un Animal, un Environnement ou un Contenu.

        Sinon tu repenses à tes fonctions de ta classe mère, peut-être peux-tu réorganiser ta logique de façon que toutes les méthodes dont tu as besoin sont disponible à partir d'un pointeur de la classe mère.

        Mais petite question... Quel est le lien entre Contenu, Animal et Environnement?
        • Partager sur Facebook
        • Partager sur Twitter
          10 avril 2008 à 15:48:23

          Depuis quand le transtypage n'est-il pas très propre .... de deux choses l'une, soit ta classe mère est abstraite et contient des méthodes virtuelles dans ce cas tu utilise un tableau de pointeur sur Contenu et tu appelle tes méthodes sans t'en soucier puisque tu fera appel au polymorphisme, soit ta méthode n'est que dans la classe fille et à ce moment la tu cast ton pointeur sur Contenu en Pointeur sur ta classe fille et tu fais appel à ta fonction comme tu le ferais normalement.
          • Partager sur Facebook
          • Partager sur Twitter
            10 avril 2008 à 15:59:01

            C'est à utiliser avec parsimonie car le programme est plus gros et plus lent dû au fait que le cast se fait à l'exécution et non à la compilation.

            http://h-deb.clg.qc.ca/Sujets/Divers--cplusplus/CPP--Casts-ISO.html
            • Partager sur Facebook
            • Partager sur Twitter
              10 avril 2008 à 15:59:18

              Citation : Pas de titre

              Depuis quand le transtypage n'est-il pas très propre ....


              Uniquement certains et dans certaines conditions. Le downcasting en est un, et 90% des cas où les gens l'utilisent sont sales.

              Pour plus de détails il y a ribambelle d'endroits qui en parlent sur le net, genre les FAQ de C++, par exemple celle de developpez.com.
              • Partager sur Facebook
              • Partager sur Twitter
                10 avril 2008 à 21:04:13

                J'ai lu quelquepart qu'il s'agit du polymorphisme dynamique : tu peux faire un tableau de pointeurs vers des Contenu* et tu peux ensuite envoyer des classes filles. Sinon la classe fille est convertie en classe mère pour revenir dans le trableau
                • Partager sur Facebook
                • Partager sur Twitter
                  10 avril 2008 à 21:10:50

                  Citation : aleksab

                  J'ai lu quelquepart qu'il s'agit du polymorphisme dynamique : tu peux faire un tableau de pointeurs vers des Contenu* et tu peux ensuite envoyer des classes filles. Sinon la classe fille est convertie en classe mère pour revenir dans le trableau



                  Elle n'est pas convertie, seulement interpretée comme tel. La preuve est que lorsqu'on créer un tableau d'objets de classe héritée et qu'on passe le tableau à une fonction en tant que pointeur de la classe mère, je vous promet beaucoup de plaisir lors de la lecture du 2e élément!
                  • Partager sur Facebook
                  • Partager sur Twitter
                    11 avril 2008 à 12:23:53

                    Désolé de ma réponse tardive.

                    En fait on m'a conseillé effectivement de rendre la classe Contenu abstraite, avec des méthodes virtuelles qui seront définies dans les classes filles.

                    En revanche le programme va demander beaucoup de fois de traiter ces méthodes, est-ce vrai que ça va demander plus de ressources que de coutume?
                    Tab sera un tableau de pointeurs vers Contenu je pense, un tableau d'objets étant beaucoup trop lourd.

                    Merci pour vos réponses en tout cas.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 avril 2008 à 13:41:11

                      Non, cela ne va pas demander plus de temps que de faire des "if".

                      A cause du polymorphisme, un tableau d'éléments de la classe abstraite n'est pas envisageable, l'indirection via un pointeur est NECESSAIRE.
                      • Partager sur Facebook
                      • Partager sur Twitter
                      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                        11 avril 2008 à 14:49:28

                        Le programme va être plus gros mais ça ne prendra pas plus de temps à utiliser la fonction qu'à copier l'adresse d'un pointeur (ou d'un if, c'est 1 instruction)

                        Le polymorphisme peut être une solution mais je ne comprend vraiment pas le rapport hierarchique entre tes 3 noms de classe.

                        Si c'est seulement pour faciliter l'utilisation d'un tableau pour tout tes objets alors c'est une mauvaise utilisation. Ça c'est pour C# ou Java. Il n'y a pas de mot-clé "as" en C++.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          11 avril 2008 à 14:50:08

                          ton tableau:

                          std::vector<Contenu *>

                          1. class Contenu{
                          2.     ...
                          3.     public:
                          4.     virtual ~Contenu(){}
                          5.     virtual Contenu* create() = 0; // contructeur virtuel
                          6.     ...
                          7. }


                          Et une classe fille
                          1. class Environement : public Contenu{
                          2.     ...
                          3.     public:
                          4.     virtual ~Environement (){...}
                          5.     virtual Contenu* create( ... ){
                          6.        ... //code de ton constructeur
                          7.        return new Environement();
                          8.    }
                          9. }


                          La Doc ici:
                          http://jlecomte.ifrance.com/c++/c++-faq-lite/virtual-functions-fr.html

                          Edit Shape*
                          • Partager sur Facebook
                          • Partager sur Twitter
                            11 avril 2008 à 15:55:09

                            Citation : Shargat

                            Désolé de ma réponse tardive.

                            En fait on m'a conseillé effectivement de rendre la classe Contenu abstraite, avec des méthodes virtuelles qui seront définies dans les classes filles.

                            En revanche le programme va demander beaucoup de fois de traiter ces méthodes, est-ce vrai que ça va demander plus de ressources que de coutume?
                            Tab sera un tableau de pointeurs vers Contenu je pense, un tableau d'objets étant beaucoup trop lourd.

                            Merci pour vos réponses en tout cas.



                            Si ta classe Contenu est abstraite tab est OBLIGATOIREMENT un tableau de pointeur sur Contenu car il est impossible d'instancier un objet de la classe abstraite tout comme les méthodes virtuelles pures ne doivent pas etre définie dans la classe mère... Cependant pour ce qui est de la vitesse d'exécution de ton programme, si c'est un exercice tu ne verras pas la différence mais surement que pour un programme plus gros cela pourrait jouer du fait que le typage se fait à l'éxécution du programme.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              14 avril 2008 à 22:23:56

                              Très bien, merci à vous, j'ai pris note de vos remarques. ^^

                              Je vais donc utiliser Contenu en classe virtuelle.
                              Voici sa déclaration dans mon .h

                              class Contenu
                              {
                                	private :
                              		//Attributs
                              		std::string _nomTypeContenu; //prend la valeur CONTENU_ANIMAL ou CONTENU_VIDE
                              		int _x; //Abscisse de la case
                              		int _y; //Ordonnée de la case
                              
                              	public :
                              		//Méthodes
                                              //Contenu(std::string = CONTENU_VIDE, int = 0, int = 0); //Constructeur
                              		void setAbscisse(int x) { _x = x;};
                              		void setOrdonnee(int y) {_y = y;};
                              		bool operator == (Contenu) const; //surdéfinition de l'opérateur de comparaison;
                                      virtual void deplacer(const int[][MAX]) = 0; //Déplacement d'un animal
                              		virtual void retirer(int [][TAILLE_REELLE]) = 0; //Retire un animal
                              };
                              


                              Et voici la déclaration de ses classes dérivées :

                              //classe fille de Contenu
                              class Animal : public Contenu
                              {
                                  protected :
                              		//Attributs
                              		int _population ;
                              
                              	public :
                              		//Méthodes
                              		Animal(int = 0) ; //Constructeur
                              		virtual void deplacer(const int[][MAX]); //Déplacement d'un animal
                              		virtual void retirer(int [][TAILLE_REELLE]); //Retire un animal
                              };
                              
                              //classe vide fille de Contenu
                              class Vide : public Contenu
                              {
                                  //vide
                              };
                              
                              //classe mur
                              class Mur : public Contenu
                              {
                              };
                              


                              Et enfin, les classe elles-mêmes dérivées de la classe Animal :

                              //classe fille de Animal et petite fille de Contenu
                              class Poule : public Animal
                              {
                              	private :
                              		//Attributs
                                      int _nbPv ;
                              
                                      //variables statiques
                                      static  char _predateurPoule;
                                      static  char _proiePoule;
                                      static int _nbPoule;
                              
                              
                              	public :
                              		//Méthodes
                              		Poule(int = 50); //Constructeur
                              		int getNbPv() { return _nbPv;};
                              };
                              
                              //classe fille de Animal et petite fille de Contenu
                              class Renard : public Animal
                              {
                              	private :
                              		//Attributs
                              		int _nbPv;
                              
                              		//vriables statiques
                                      static char _proieRenard;
                                      static char _predateurRenard;
                              		static int _nbRenard;
                              
                              
                              	public :
                              		//Méthodes
                              		Renard(int =  50);//Constructeur
                              
                              };
                              
                              
                              //classe fille de Animal et petite fille de Contenu
                              class Vipere : public Animal
                              {
                              	private :
                              		//Attributs
                              		int _nbPv ;
                              
                              		//variables statiques
                                      static char _proieVipere;
                                      static char _predateurVipere;
                              		static int _nbVipere;
                              
                              	public :
                              		//Méthodes
                              		Vipere(int =  50);//Constructeur
                              
                              };
                              



                              Comme ça le problème est posé. :)

                              Je n'ai pas encore vu la notion de classe abstraite, mais j'ai compris son fonctionnement.
                              J'ai mis le constructeur de "Contenu" en commentaire. Ai-je le droit de créer cette classe en laissant le constructeur par défaut, sachant qu'elle est virtuelle?

                              Car en fait quand je teste ce main :

                              int main() {
                              
                                  Contenu c1;
                                  Poule p1;
                              
                                  P1 = C1;
                              
                                  cout << "le nombre de points de vie est " << p1.getNbPv() << endl;
                              
                                  return 0;
                              
                              }
                              


                              J'obtiens l'erreur suivante :

                              error : cannot declare variable 'c1' to be of type 'Contenu'
                              error : because the following functions are abstract
                              error : virtual void Contenu::retirer(int (*)[8])
                              error : virtual void Contenu::deplacer(const int (*)[100])

                              error : no match for 'operator= ' in 'p1 = c1'

                              Dois redéfinir l'opérateur d'affectation? L'opérateur par recopie ne fonctionne pas entre une classe mère et sa dérivée?
                              Merci d'avance à ceux qui veulent bien m'éclairer sur cette notion de classes virtuelles. Pourquoi ici elles posent problèmes? :euh:

                              • Partager sur Facebook
                              • Partager sur Twitter
                                14 avril 2008 à 22:36:44

                                En C++, il faut explicitement utiliser des pointeurs. Contrairement à Java où le type pointeur est le type par défaut (les références Java n'étant que des pointeurs déguisés pour ne pas faire peur)

                                PS: "classe virtuelle" ne veut rien dire en C++.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                  14 avril 2008 à 22:44:56

                                  Citation : lmghs

                                  En C++, il faut explicitement utiliser des pointeurs. Contrairement à Java où le type pointeur est le type par défaut (les références Java n'étant que des pointeurs déguisés pour ne pas faire peur)

                                  PS: "classe virtuelle" ne veut rien dire en C++.



                                  Ok je suppose qu'on parle plutôt de Classes abstraites.

                                  En ce qui concerne les pointeurs, je remplace mon main par ceci :

                                  int main() {
                                  
                                      Contenu c1;
                                      Contenu *c;
                                      Poule p1;
                                      Poule *p;
                                  
                                      c = &c1;
                                      p = &p1;
                                  
                                      *p = *c;
                                  
                                    cout << "le nombre de points de vie est " << (*p).getNbPv() << endl;
                                  
                                      return 0;
                                  
                                  }
                                  


                                  L'erreur liée à l'opérateur d'affectation disparait, mais les autres erreurs persistent.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    14 avril 2008 à 22:54:27

                                    Normal, tu as gardé dans ton main() le code où tu manipules directement des objets pourtant non instanciables...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                      14 avril 2008 à 22:59:39

                                      Ah mince, je ne peux instancer d'objets de type Contenu c'est ça?

                                      En revanche, puis-je créer un tableau de ce type:

                                      Contenu tab[MAX];
                                      Poule p1;
                                      
                                      tab[1] = p1;
                                      


                                      J'initialise le tableau avec des objets de types Contenu mais ils ne sont pas explicitement instancés...C'est correct ?
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        14 avril 2008 à 23:03:30

                                        Non.
                                        Non.
                                        et non.

                                        Contenu est abstraite donc non instanciable.

                                        Un tableau de Contenu contient des Contenus (sic). Or Contenue n'est toujours pas instanciable.
                                        Même si elle l'était, le fait quelle soit dérivée (publiquement) fait qu'il est peu probable que cela soit une bonne idée.

                                        Quant à la dernière affectation, c'est définitivement pas une bonne idée quand il y a de l'héritage dans l'air. Mais de toutes façons, Contenu n'est toujours pas instanciable ...
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                          14 avril 2008 à 23:12:31

                                          En fait le but ce serait que ce tableau puisse contenir des Poules et des Renard et des Vipères, ou toute autre objet dérivé de Contenu.
                                          C'est pour ça que j'avais déclaré un tableau de Contenu

                                          Dans ce cas comment gérer cela ?

                                          (merci de ta patience ^^)
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            14 avril 2008 à 23:20:08

                                            Il te faut un tableau de pointeurs sur Contenu.
                                            Ou encore un std::vector<Contenu*> (qui a l'avantage de gérer sa mémoire comme un grand)
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                              14 avril 2008 à 23:30:51

                                              Merci beaucoup, je vais me pencher sur la solution du tableau de pointeurs (vector m'étant encore totalement inconnu, je suis en 1ère année de DUT informatique).

                                              Je me permets de garder la discussion ouverte car j'aurai surement d'autres questions sur ce problème d'héritages, je pense notamment à l'accès aux méthodes virtuelles.

                                              Merci en tout cas.

                                              EDIT:
                                              j'ai une nouvelle question : :D

                                              Si maintenant, j'ajoute à la classe Animal, une classe soeur que j'appelle Vide.
                                              Vide est donc la dérivée de Contenu.
                                              Or cette classe Vide n'a pas elle-même de dérivée. Est-ce que cela implique que si je veux instancer un objet de type Vide, je dois y définir toutes les méthodes virtuelles qui sont dans la classe Contenu ?

                                              Car alors je risquerai de me retrouver avec une erreur de type :

                                              error : cannot declare variable 'v1' to be of type 'Vide'
                                              error : because the following functions are abstract
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                15 avril 2008 à 15:44:01

                                                Tu n'as pas redéclarer tes fonctions qui sont virtuelles pures dans la classe mère donc la classe Vide (et Mur) reste abstraite. Tu ne peux pas l'instancier.

                                                Il te faut redéfinir les fonctions...
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  15 avril 2008 à 18:04:19

                                                  Je ne sais pas si définir une classe vide a un interret, comme tu as un tableau de pointeur il te suffit de le remplir de null à l'endroit ou il est vide.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    15 avril 2008 à 18:25:41

                                                    Ok merci beaucoup ça m'a bien éclairé.

                                                    L'intérêt de la classe vide viendra après, dans l'avancement du projet, pour anticiper d'éventuels attributs caractéristiques.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter

                                                    Héritage et accès aux classes

                                                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                    • Editeur
                                                    • Markdown