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++Builder Discussion :

Template et Héritage [Langage/Algorithme]


Sujet :

C++Builder

  1. #1
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 449
    Points : 24 856
    Points
    24 856
    Par défaut Template et Héritage
    C++ Builder 2007
    Pas encore de TList<> générique disponible, en plus, j'ai cru lire que le générique Delphi utilisée comme template C++, cela n'était pas le top .. si quelqu'un à retour la dessus, est-il possible en 2009 ou XE, d'écire TList<MonTypeCPPAMoi>
    Car, dans la Doc "Si le code C++ tente d'utiliser un générique Delphi pour les types qui n'étaient pas instanciés dans Delphi, vous obtiendrez des erreurs lors de la liaison." est inquiétant

    Donc, C++ Builder 2007, je me lance dans les templates, en Delphi 7, cela n'existe pas, je découvre et un gros problème se pose

    Exemple une TObjetList où l'on est pas obligé de transtyper tout le temps !

    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
    template<class T>
    class TShaiList : public TObjectList
    {
    public:
      // Opérateurs Publiques
      T* operator[](int Index) { return Items[Index]; } // Cache TObjectList[]
     
    protected:
      // Accesseurs
      T* __fastcall GetItem(int Index) {return (T*)inherited::Items[Index];}
     
    public:
      // Méthodes Protégées
      int IndexOf(T* Obj);
     
      // Propriétés Publiques
      __property T* Items[int Index] = {read=GetItem}; // default []
    };
     
    template<class T>
    int TShaiList<T>::IndexOf(T* Obj)
    {
      for (int i = 0; i < Count; i++)
      {
        if (Items[i]->IsEquals(Obj))
          return i;
      }
     
      return -1;
    }
    Deux spécialisations

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class TBidule : public TObject
    {
     // Rien !
    }
     
    class TBiduleList : public TShaiList<TBidule>
    {
    ...
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class TMachin : public TObject
    {
    public 
      bool IsEquals(TMachin *Obj);
     
    }
     
    class TMachinList : public TShaiList<TMachin>
    {
    ...
    }
    Si l'on utilise TMachinList->IndexOf, ça compile, ça fonctionne !
    Si l'on utilise TBiduleList ->IndexOf, ça compile pas ! forcément IsEquals ne fait pas parti de TBidule

    En fait, le template, il faut le coder à l'aveugle et ne surtout rien supposer de T

    Dans mon vrai projet, j'ai donc déplacé IndexOf de TShaiList vers TMachinList , là où je sais que IsEquals existe !

    Existe-il un moyen pour que T hérite d'une classe ?
    Exemple de code que je voudrais qui n'existe pas !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class TComparableObjet
    {
      virtual IsEquals(TComparableObjet*Obj) = 0; // abstract
    }
     
    template<class T : public TComparableObjet>
    class TShaiList : public TObjectList
    ...
    Et que le compilateur protège contre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class TBidule : public TObject
    {
     // Rien !
    }
     
    class TBiduleList : public TShaiList<TBidule> // Compile pas TBidule n'est pas un TComparableObjet 
    {
    ...
    }

    mais accepte ça évidemment

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class TMachin : public TComparableObjet
    {
    public 
      bool IsEquals(TMachin *Obj); // override;
     
    }
     
    class TMachinList : public TShaiList<TMachin>
    {
    ...
    }
    Est-ce déjà ma question est pertinente ?
    En fait je veux une générique limité à une branche d'objet !

    J'ai vu que l'on pouvait utiliser les typedef pour limiter le typename !
    Je n'ai pas bien compris la syntaxe d'ailleurs ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  2. #2
    Membre averti

    Profil pro
    Inscrit en
    Juin 2005
    Messages
    351
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 351
    Points : 446
    Points
    446
    Par défaut
    Moi je ferai une classe abstraite d'interface dont doit descendre le type *T avec un static_cast<> dans le template:

    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
    class IMinimum {
      bool IsEquals(TMachin *Obj) = 0;
    }
    
    template<class T>
    int TShaiList<T>::IndexOf(T* Obj)
    {
      for (int i = 0; i < Count; i++)
      {
        if (static_cast<IMinimum*>(Items[i])->IsEquals(Obj))
          return i;
      }
     
      return -1;
    }
    Je pense (à vérifier) que le static_cast ne compilera pas avec:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class TBidule : public TObject
    {
     // Rien !
    }
     
    class TBiduleList : public TShaiList<TBidule>
    {
    ...
    }
    Mais bien avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class TMachin : public TObject, public IMinimum
    {
    public 
      bool IsEquals(TMachin *Obj);
      
    }
     
    class TMachinList : public TShaiList<TMachin>
    {
    ...
    }
    Le problème est que tous les types que tu veux utiliser dans ton template doivent hériter de IMinimum. Par exemple, le cas TMachin que tu donnes ne compilera pas si tu n'as pas ajouté mon code en rouge

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 449
    Points : 24 856
    Points
    24 856
    Par défaut
    Merci !
    C'est une interface ou une classe abstraite pure ?
    je ne connais que le mot clé VCL "interface" (IUnknown, ...) du Delphi !
    Mais effectivement, c'est une Bonne Approche !
    Cela tombe bien, j'ai déjà cette classe ancêtre commune aux différents Items des différentes listes !
    Elle n'est pas abstraite mais ça fera l'affaire, effectivement, j'ai bien une erreur de compilation si Items n'hérite pas de ma classe ancêtre (j'ai testé avec TComponent compile pas, TObject ça compile mais bon ça ira)

    Je continue à pousser le vice, j'ai des listes associatives un pointeur sur struct associé à un objet (oui bizarre, j'ai du faire une rustine sur un code existant que j'essaye de modifier le moins possible)
    C'est un peu comme une TBucketList mais profitant du OwnObjects de la TObjectList !

    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
    //---------------------------------------------------------------------------
    //                    TShaiGenericObjectAssociationList                    -
    //---------------------------------------------------------------------------
    template<class T, class A>
    class TShaiGenericObjectAssociationList : public TObjectList
    {
      typedef TObjectList inherited;
     
    public:
      // Opérateurs Publiques
      T* operator[](A AAssociation) { return GetItem(AAssociation); } // Cache TObjectList[]
     
    protected:
      // Accesseurs
      T* __fastcall GetItem(A AAssociation); // la liaison entre T et A doit être spécialisé
      T* __fastcall GetItemByIndex(int Index);
     
      // Propriétés Protégées
      __property T* ItemByIndex[int Index] = {read=GetItemByIndex};
     
    public:
      // Propriétés Publiques
      __property T* Items[A AAssociation] = {/*read=GetItem*/}; // default [] //
    };
     
    //---------------------------------------------------------------------------
    template<class T, typename A>
    T* __fastcall TSygalGenericObjectAssociationList<T, A>::GetItemByIndex(int Index)
    {
      return (T*)inherited::Items[Index];
    }
    "T* Items[A AAssociation]" et "T* GetItem(A AAssociation)" provoque une belle erreur "Non concordance de paramètre dans le spécificateur d'accès 'spécificateur' de la propriété 'propriété' (E2347)"

    semble que le template et __property ne peuvent pas aller jusqu'au bout du délire !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Membre averti

    Profil pro
    Inscrit en
    Juin 2005
    Messages
    351
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 351
    Points : 446
    Points
    446
    Par défaut
    Je parlais d'interface au sens "fonctions visibles" mais à ma connaissance il n'y a pas en C++ de système explicite d'interface comme en Java ou IUnknown de Delphi. J'avais en tête une class abstraite pure sans variable de classe (pour la l'héritage avec TComponent qui ne les supporte pas).

    Pour les propriétés, je ne peux malheureusement pas t'aider, mais je sais que le système n'aime pas trop les types "exotiques" (terme que je ne peux pas définir plus précisément)

    Patrick

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 449
    Points : 24 856
    Points
    24 856
    Par défaut
    J'avais bien compris, c'était le I... comme Interface qui me chagrinnait !
    Dans une spécialisation partielle j'ai pu introduire le static_const

    Tiens, encore un truc bizarre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    protected:
      // Accesseurs
      T* __fastcall GetItem(A AAssociation); // la liaison entre T et A doit être spécialisé
    si j'écris

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Type1, Type2 sont déclaré ailleurs !
    class Specialisation : public TShaiGenericObjectAssociationList<Type1, Type2*>
    {
    ...
      __property Type1* Items[Type2* Params] = {read=GetItem}; // default []
    }
    Note la redéclaration de Items pour enfin que GetItem soit lié comme accesseurs puisque en template ça passait pas !

    Dans le .CPP
    Ceci ne compile pas, il me dit que GetItem n'existe pas dans Specialisation
    Pourtant Specialisation étant un TShai... je pensais qu'il récupérait le GetItem prototype (comme il le gère avec Items[])
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Type1* __fastcall Specialisation::GetItem(Type2* Params) 
    {
    ...
    }
    Je suis obligé de l'écrire comme cela ! ce qui est un peu lourd
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<>
    Type1* __fastcall TShaiGenericObjectAssociationList<Type1, Type2*>::GetItem(Type2* Params)
    {
    ...
    }
    J'ai essayé d'autres variante mais la liaison ne passe qu'avec cette syntaxe !
    Un peu bizarre !


    Pour simplifier mon code j'ai donc fait un typedef (+ les cartouches de code, je ne risque pas de me tromper)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Type1, Type2 sont déclaré ailleurs !
    type TShaiGenericObjectAssociationList<Type1, Type2*> SpecialisationBaseTemplate
    class Specialisation : public SpecialisationBaseTemplate 
    {
    ...
      __property Type1* Items[Type2* Params] = {read=GetItem}; // default []
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<>
    Type1* __fastcall SpecialisationBaseTemplate::GetItem(Type2* Params)
    {
    ...
    }
    le typedef donne cohérence au code, évite que je confonde les variantes <T, A> où une erreur de frappe non détecté par le compilateur mais qui va échouer à la liaison !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Template et héritage
    Par Ulmo dans le forum Langage
    Réponses: 16
    Dernier message: 08/03/2009, 23h41
  2. Template et héritage
    Par rooger dans le forum Langage
    Réponses: 5
    Dernier message: 22/07/2008, 13h48
  3. Foncteur, classes templates et héritage
    Par Floréal dans le forum C++
    Réponses: 8
    Dernier message: 17/06/2007, 21h56
  4. Template ou héritage
    Par bolhrak dans le forum Langage
    Réponses: 6
    Dernier message: 22/12/2006, 11h22
  5. patron, templates et héritages!
    Par kleenex dans le forum C++
    Réponses: 4
    Dernier message: 05/06/2006, 22h57

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