Forum Programmation.c++ templates et héritage.

Posté par  .
Étiquettes : aucune
0
30
nov.
2004
Dans un projet, pour faire propre, j'aurais besoin de l'héritage de templates...
Mais voilà, pour des contraintes d'architecture, certaines classes héritent
d'instanciations de templates.
Jusqu'ici rien à dire.
La ou ça ce corse c'est que j'ai besoin du mécanisme d'héritage, non pas du template lui-même, mais de ses paramètres.

exemple :

subTopParam hérite de topParam.

on a une fonction de test :

void test (top &t) {
cout << "test passé" << endl;
}


j'essaie de l'appeler avec un top ce qui ne devrait poser aucun problème puisque subTopParam hérite de topParam

int main(int argc, char *argv[]){
top t;
test(t)
}


Mais voilà :

testtempleates.cpp:42: error: invalid initialization of reference of type '
top&' from expression of type 'top'
testtempleates.cpp:35: error: in passing argument 1 of `void
test(top)'



il n'arrive pas à me compiler le truc
  • # erratum

    Posté par  . Évalué à 1.

    AARG, y'a un truc qu'est pas passé je remet la sortie de gcc:
    testtempleates.cpp:42: error: invalid initialization of reference of type '
    top&' from expression of type 'top'
    testtempleates.cpp:35: error: in passing argument 1 of `void
    test(top&)'

    plusieurs essais pour le mettre dans le commentaire ...


    non bah les types de paramètre de templates ils passent pas ... c'est pas des balises bordel ! :/
    • [^] # Re: erratum

      Posté par  . Évalué à 1.

      tu pourrais pas mettre une plus grosse partie de ton code source? parceque ton explication du problème est un peu trop flou...dans ton exemple y a même pas la moindre trace de template...
      difficile de t'aider dans ces conditions...
    • [^] # Re: erratum

      Posté par  . Évalué à 2.

      Pour les chevrons des template : &lt; donne < et &gt; donne >.

      Je suppose que pour ton code, tu as quelque chose du genre :

      template <typename T>
      class top
      {
      };


      Pourrais-tu poster un bout de code avec les templates ?
      • [^] # Re: erratum

        Posté par  . Évalué à 1.

        Merci pour les chevrons, j'en avais besoin ;) je ne m'en étais pas aperçus.
        voilà le message que je voulais poster :


        Dans un projet, pour faire propre, j'aurais besoin de l'héritage de templates...
        Mais voilà, pour des contraintes d'architecture, certaines classes héritent
        d'instanciations de templates.

        Jusqu'ici rien à dire.

        La ou ça ce corse c'est que j'ai besoin du mécanisme d'héritage, non pas du template lui-même, mais de ses paramètres.

        exemple :
        subTopParam hérite de topParam.
        on a une fonction de test :

        void test (top<topParam> &t) {
        cout << "test passé" << endl;
        }


        j'essaie de l'appeler avec un top<subTopParam> ce qui ne devrait poser aucun problème puisque subTopParam hérite de topParam
         int main(int argc, char *argv[]){
        top t<subTopParam>;
        test(t);
        }

        Mais voilà :
         testtempleates.cpp:42: error: invalid initialization of reference of type '
        top<topParam>&' from expression of type 'topt<subTopParam>'
        testtempleates.cpp:35: error: in passing argument 1 of `void
        test(top<topParam>&t)'


        petit ajout :

        Il semble que gcc (et l'ISO C++ sans doute) ne permet pas de stocker une instance de template avec de paramètre compatibles avec la l'instance de déclaration.
        J'espère être à peu près clair, mon problème n'est pas évident, je veux juste savoir si ce dont j'ai besoin est possible ou pas (ou s'il y a des bidouilles pas trop crades pour le faire)
        • [^] # Re: erratum

          Posté par  . Évalué à 3.


          void test (top<topParam> &t) {
          cout << "test passé" << endl;
          }

          j'essaie de l'appeler avec un top ce qui ne devrait poser aucun problème puisque subTopParam hérite de topParam


          Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents. C'est donc normal que ça plante. C'est un peu dans le même genre que l'exemple garage de voitures/garage de véhicules de la FAQ lite (http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-2(...) ).

          À mon avis, la solution la plus propre et la plus simple est de faire de test une fonction template :

          template<typename T>
          void test (top<T> & t) {
          cout << "test passé" << endl;
          }

          Et dans cette fonction de tester si le type T dérive bien de topParam. La bibliothèque boost fournit des classes de trait permettant de tester ce genre de choses (cf. boost::is_base_and_derived, http://www.boost.org/libs/type_traits/#relationships(...) ). Si tu ne veux/peux pas utiliser ce genre de choses, il faudra faire joujou avec static_cast, pour transformer un T* en topParam*, et voir si ça passe. Il te faudra ensuite gérer le cas où T ne dérive pas de topParam (lancer une exception, prévoir un comportement par défaut, ...).

          Le problème vient du fait que tu mélanges du polymorphisme statique (résolu à la compilation, les templates) et du polymorphisme dynamique (résolu à l'exécution, l'héritage). As-tu vraiment besoin de faire ce genre de choses ?

          Ce qu'on voit en général dans l'utilisation des templates (cf. la bibliothèque standard du C++, notamment les itérateurs et les algorithmes), c'est une doc genre "le paramètre Machin doit avoir telle propriété". Si l'utilisateur ne respecte pas les préconditions, tant pis, il n'avait qu'à lire la doc :-)
          • [^] # Re: erratum

            Posté par  . Évalué à 1.

            Ok, c'est bien ce que j'avais compris en réfléchissant un peu plus sur le problème.
            Mais en fait, l'exemple que je donne ne reflète pas completement le contenu de mon projet, il l'illustre simplement.

            Mais j'aimerais discuter de ceci :
            Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents.

            En fait, après avoir pris connaissance de l'article de la FAQ Lite, T1 et T2 ne sont pas du même type au sens "C" du terme (en gros il ne font pas la même taille).
            Mais d'un point de vue objet, si T2 hérite de T1, un truc du type top<T1> peu référencer top<T2> , puisque, apriori, tous les comportements de T2 sont compatible avec T1.


            Bon pour revenir à mon projet :

            finallement j'ai besoin de ça :

            top<class MACHIN> {
            virtual void fonc (MACHIN &, vector<MACHIN *> &) const =0;
            };

            class T1 {};

            class topSpe : top<T1> {
            void fonc (T1&, vector<T1*>&);
            };

            class T2 : public T1 {
            }

            int main () {
            topSpe t;
            T2 d;
            vector<T2*> v;
            t.fonc(T2, v);
            }

            c'est un peu plus tordu que ca mais ca y ressememble, et ca ne marche pas ...
            pour le problème déjà cité et pour la définition de top::fonc.
            voilà, je suis preneur d'idées et de sugestions....

            PS : j'ai besoin d'un truc tordu car je veux définir un truc abstrait pour manipuler des objets, qui est dérivé pour être utilisé concretement, chaque dérivation permettant des manipulations dans différents contextes.
            je me demande si c'est possible, et qu'en complexifiant le truc à mort je n'ai pas masqué l'infaisabilité.
            • [^] # Re: erratum

              Posté par  . Évalué à 1.

              Ben si, ça pose problème : même si deux types T1 et T2 sont reliés par héritage, top<T1> et top<T2> sont deux types bien différents.

              En fait, après avoir pris connaissance de l'article de la FAQ Lite, T1 et T2 ne sont pas du même type au sens "C" du terme (en gros il ne font pas la même taille).
              Mais d'un point de vue objet, si T2 hérite de T1, un truc du type top<T1> peut référencer top<T2> , puisque, apriori, tous les comportements de T2 sont compatible avec T1.


              Dans ce cas, l'important n'est pas les comportments de T1 et de T2, mais ceux des templates associés top<T1> et top<T2>. On pourrait a priori penser que si T1 et T2 ont le même comportement, les templates auront fatalement le même. Ca marcherait bien si le C++ ne comportait pas de spécialisation des templates, qui te permet d'avoir des comportements différents, et donc des définitions différentes, pour certains paramètres du template. L'exemple classique est std::vector<bool> qui dans certaines implémentations de la SL n'est pas implémenté de la même façon que ses petits camarades std::vector<int> ou std::vector<char>.

              L'exemple de code que tu donnes marche si la fonction fonc ne prend qu'un T est pas de vecteur de T. C'est le vecteur qui pose problème : un conteneur de T2* n'est pas un conteneur de T1*, et virer les pointeurs ne change pas le problème.

              La solution qui me parait la plus simple est de ne pas construire des vecteurs de T2*, mais des vecteurs de T1*, et de vérifier dans topSpe::fonc que les T1* du vecteur pointent bien sur des vrais T2* (dynamic_cast est ton ami).
          • [^] # Re: erratum

            Posté par  . Évalué à 3.

            très bonne annalyse!

            Sinon sans avoir besoin de passer par Boost, on peut faire en sorte que la classe top< donne < topParam > donne > dérive d'une classe topBase :

            topBase{
            ...
            };

            template< typename T >
            class top : public topBase {
            ...
            };

            et garder
            void test (top< topParam> &t) {
            cout << "test passé" << endl;
            }

            mais bien sûr on n'a aucune grarantie que subTomParam hérite de topParam...et si test() à besoin d'acceder a subTopParam comme si c'était un topParam alors qu'en réalité subTopParam ne dérive pas de topParam, t'aura une erreur de compilation...

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.