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 :

Probleme de conception sur heritage virtuel et template


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Points : 23
    Points
    23
    Par défaut Probleme de conception sur heritage virtuel et template
    Bonjour, j'ai une question de base sur le couplage heritage virtuel/ template qui m'embete depuis un moment. Je l'expose sur un cas tres simple, et sans aucun interet pratique.

    Pour le mariage, c'est le tric standard "TypeErasure" si je ne m'abuse. Mmmm j'ai feuillete le tuto de Alp Mestan "Mariage de la Programmation Orientee Objet et de la Programmation Generique: TypeErasure".
    Bon, donc je pars une classe de base "Object" implementant une fonction virtuelle pure, disons "fonction". Puis je derive une classe template "ObjectImplemented" a un parametre. Cette classe est juste un "squelette" en ce sens qu'elle ne doit jamais etre instanciee. Elle ne sert que de base pour ecrire N classes specialisees.
    Cela etant, je cree ensuite une classe "CompositeObject" ayant pour membre un vector<Object*> nomme "liste" disons. Mon probleme est alors du "genre": je veux construire un constructeur par copie (disons qu'il prenne en parametre "liste_source"). Bon, clairement j'expose le probleme sur le cas du constructeur par copie mais il survient dans beaucoup d'autres types d'operations... Pour le regler, je n'ai rien trouver de mieux que de proceder ainsi:
    - la classe de base "Object" possede un membre "int type"
    - chaque classe specialisee "ObjectImplemented<T>" definit "type" de maniere univoque
    - pour chaque element de "liste_source", je teste son type et en fonction, i.e dans un if, je fais un new sur la classe template specialisee associee.

    Bon, mon probleme c'est que dans mes implementations concretes, le nombre de specialisationest tres grand (genre 100) et je dois donc me taper
    une sorte de "if(type==0){ new ObjectImplemented<T0> }else if(type==1000) {new ObjectImplemented<T100>" geant ce qui est tres long et penible....
    Bon, je pense que je ne procede pas du tout de la bonne maniere donc si vous pouviez m'indiquer la demarche standard pour ce genre de souci ca serait cool... Je pense a definir une fonction virtuelle d'instanciation dans "Object", fonction que j'implemente concretement dans mes classes derivees specialisees (cf. section "CECI EST UNE AUTRE IDEE" dans le code ci-dessous). Est-ce bon?

    Ci-dessous, je joins un code source :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    //-----------------------------------------------------------------------------
    //Classe de base, virtuelle pure
    //-----------------------------------------------------------------------------
    class Object 
    {
    public:
      virtual void fonction() = 0;
      //Pour garder trace des enfants implementant la classe:
      static int type = 0; 
      //CECI EST UNE AUTRE IDEE:
      virtual bool instancie(Object* source) = 0;
    };
     
     
    //-----------------------------------------------------------------------------
    //Classe derivee template. Sert juste de "squelette" pour specialisation.
    //-----------------------------------------------------------------------------
    template<int T>
    class ObjectImplemented : public Object
    {
    public:
      //Mum, bon ca aussi je ne suis pas sur que ce soit tres "professionnel"
      //Comment je peux faire plus correctement???
      ObjectImplemented()
      {
        cout << "FATAL: this class should never be instancied" << endl;
        exit(1);
      }
    };
     
    //-----------------------------------------------------------------------------
    //Specialisation effective 1. Implemente la virtualite.
    //-----------------------------------------------------------------------------
    template<>
    class ObjectImplemented<1> : public Object
    {
    public:
      ObjectImplemented()
      {
        //Definit <type>
        type=1;
      }
      void fonction()
      {
        //Bla, bla, bla...
        cout << "Je suis T1" << endl;
      }
      //CECI EST UNE AUTRE IDEE:
      bool instancie(Object* source)
      {
        if(source==0)
          {
    	source = new ObjectImplemented<2>();
    	return true;
          }
        else
          {
    	return false;
          }
      }
    };
     
    //-----------------------------------------------------------------------------
    //Specialisation effective 2. Implemente la virtualite.
    //-----------------------------------------------------------------------------
    template<>
    class ObjectImplemented<2> : public Object
    {
    public:
      ObjectImplemented()
      {
        //Definit <type>
        type=2;
      }
      void fonction()
      {
        //Bla, bla, bla...
        cout << "Je suis T2" << endl;
      }
      //CECI EST UNE AUTRE IDEE:
      bool instancie(Object* source)
      {
        if(source==0)
          {
    	source = new ObjectImplemented<2>();
    	return true;
          }
        else
          {
    	return false;
          }
      }
    };
     
    //-----------------------------------------------------------------------------
    //La classe composite. C'est elle qui est penible a gerer pour moi...
    //-----------------------------------------------------------------------------
    class CompositeObject
    {
    public:
      //Mon vector d'object virtuel
      vector<Object*> liste;
      //L'exemple du constructeur de copie qui m'embete:
      CompositeObject(const CompositeObject& source)
      {
        for(int i=0;i<source.size();i++)
          {
    	//Cette structure "if" m'enerve, m'enerve...
    	if(source[i]->type==1)
    	  {
    	    Object* object_aux = new ObjectImplemented<1>();
    	    liste.push_back(object_aux);
    	  }
    	else if(source[i]->type==2)
    	  {
    	    Object* object_aux = new ObjectImplemented<2>();
    	    liste.push_back(object_aux);
    	  }
    	//CECI EST UNE AUTRE IDEE:
    	Object* object_aux = 0;
    	source[i]->instancie(object_aux);
          }
      }
    };
    Bon, en esperant que j'aurais une ou deux reponses, ou au moins des liens pour me debrouiller, merci d'avance.

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Points : 23
    Points
    23
    Par défaut Re. tomayo -- errata
    Oups je viens de me relire apres avoir poste
    Heu bon donc faut pas trop faire gaffe aux erreurs de syntaxe et al: c'est source.liste au lieu de source en gros, la premiere specialisation c'est <1> au lieu de <2>, puis static int type = 0 compile pas sur tous les compilos -- cxx1x.
    Voila, bon ca reste clair sinon j'espere

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Si je comprends bien tes n classes concrètes implémenterons des fonctions virtuelles pures définies par ta classe de base? Parce que dans ce cas, pour règler le problème de l'instanciation, tu peux définir une "factory method" virtuelle pure dans ta classe de base qui retourne un pointeur de type classe de base. Ensuite, tu implémente dans chaque classe la factory method et elle te retourne une instance du bon type (elle sait lequel, celui de la classe concrète). Et hop, plus de méga if...
    Un exemple:
    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
     
    class CommonBase{
        public;
          //factory method
         virtual CommonBase* creeCopie()=0;
          //interface de service
         /*
    tout ce que j'offre comme services, bla-bla-bla
         */
         //fin interface de service
    };
     
    template <class T> 
    class CommonImplBase:public CommonBase{
       /* code apporté par le template */
    };
     
    class ObjetConcret:public CommonImplBase<Bidule>{
       public:
          //définition de la factory method
         CommonBase* creeCopie();
    };
     
    class AutreObjetConcret:public CommonImplBase<AutreBidule>{
       public:
          //définition de la factory method
         CommonBase* creeCopie();
    };
    Et les définitions:
    ObjetConcret.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CommonBase* ObjetConcret::creeCopie(){
          return new ObjetConcret(this);
    }
    AutreObjetConcret.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CommonBase* AutreObjetConcret::creeCopie(){
          return new AutreObjetConcret(this);
    }
    Concernant l'instanciation des deux classes abstraites, pas de soucis, tant que tu ne définis pas les méthodes virtuelles pures le compilo ne te laissera pas les instancier directement.
    Ici je n'ai pas défini les constructeur par copie, mais tu devras le faire si celui par défaut ne convient pas (membre pointeur par ex)
    Et pour que ce soit utile, il faut que les classes concrètes redéfinissent aussi des méthodes de service...

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Points : 23
    Points
    23
    Par défaut Re. tomayo
    Salut, c'est sympa d'avoir repondu deja
    Bon, deja tu m'as donne une piste avec cette histoire de "factory method".
    Ca formalise plus ou moins la seconde idee que je voulais mettre en place.

    Neanmoins...
    dans le code que tu propose, j'ai le souci qu'on retourne un pointeur cree en local. Mmm ca me chagrine un peu ca. T'es sur que c'est licite cette manip dans notre cas? Bon je vais tester clairement mais j'ai un gros doute. C'est pour eviter ca que ma methode prenait direct un pointeur en argument d'entree. C'est moins joli mais c'est correct au moins je crois. Si tu peux me donner ton avis la dessus c'est super

    Merci deja.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Points : 23
    Points
    23
    Par défaut Re. tomayo
    Oups, je me suis encore plante
    C'est bien ok d'allouer le pointeur dans la fonction... Me suis emmele avec les references
    Bon, du coup ta methode est bien nette pour mon probleme...
    Rereremerci

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Salut.
    le fait de retourner un pointeur créé localement est tout à fait licite. A vrai dire, passer un pointeur comme tu faisais ne résoud pas le problème: le new va créer une valeur locale pour le pointeur, et l'appelant ne la récupérera jamais.
    Ce que tu dois par contre bien définir, c'est la gestion de tes pointeurs: tu dois concevoir tes classes de manière à garder trace de ces pointeurs jusqu'à ce que tu n'en aies plus besoin, à ce moment les libérer (delete) une et une seule fois.
    Si tu ne libères pas -> fuite mémoire.
    Si tu les libères deux fois -> plantage (pour l'éviter: mets le pointeur à NULL après le delete)
    Si tu t'en sers après le delete -> corruption mémoire, trucs bizarres & co

    L'idée, c'est que ton conteneur fasse un delete sur les pointeurs de son membre vector dans son destructeur. Pour éviter qu'un pointeur resserve après avoir été détruit de cette façon, utilise toujours la copie pour transférer ton objet vers un autre pointeur (par contre si c'est juste un appel de fonction membre, pas la peine).
    [edit]je n'avais pas vu ton dernier message avant d'écrire celui-ci. Soucie toi bien de gérer la durée de vie de tes objets dynamiques (ie: créés avec new), et tout ira bien.[/edit]

Discussions similaires

  1. Réponses: 17
    Dernier message: 05/11/2013, 16h10
  2. [MLD] Probleme de conception sur quelques tables
    Par sasuke51100 dans le forum Schéma
    Réponses: 9
    Dernier message: 16/04/2012, 17h00
  3. Réponses: 6
    Dernier message: 21/07/2008, 12h15
  4. probleme sur destructeur virtuel
    Par exhortae dans le forum C++
    Réponses: 5
    Dernier message: 01/03/2008, 07h32
  5. probleme d'installation sur d'autres postes
    Par VBkiller dans le forum Composants VCL
    Réponses: 4
    Dernier message: 18/09/2002, 18h14

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