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 :

Template, héritage et polymorphisme


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 5
    Par défaut Template, héritage et polymorphisme
    Bonjour,

    J'ai un petit souci avec un code C++, une petite question d'héritage avec utilisation de template à la base, mais qui me fait soulever une autre question.

    Le code source est en pièce jointe.

    Voici la situation. Ce code fourni 2 implémentations qui sont, a priori, identiques du point de vue fonctionnelle, une utilisant des templates, et l'autre non. On peut passer de l'une à l'autre en commentant la définition #define WITH_TEMPLATE.

    Le 1er problème que je rencontre est que ces deux implémentations, a priori identique, ne se comporte pas de la même manière à la compilation : l'une passe (cell utilisant les templates), et l'autre provoque l'erreur suivante
    test.cxx: Dans function « int main(int, char**) »:
    test.cxx:53: error: no matching function for call to `Base::method(Foo*&)'
    test.cxx:24: error: candidates are: virtual bool Base::method(const Foo*&)
    Pour moi, cette erreur semble normal, puisque j'essai de faire une conversion entre un Foo*& en un const Foo*&.

    2ème problème, mais qui sans doute lié au premier, est que la version avec template, qui compile correctement, s'exécute... sans polymorphisme ! Alors qu'il devrait. Et affiche donc "Base: method" au lieu de "Child: method".

    Ne voyant pas le problème, j'appelle à l'aide. Si certains d'entre vous ont des idées là-dessus.

    Dernière chose, j'ai testé les compilateurs g++-3.3.6, g++-4.3.2 ainsi que le compilateur Comeau en ligne, et tous donne les même résultats à la compilation, donc je pense que l'on peut écarter un bug du compilo...

    Mon code
    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
    //#define WITH_TEMPLATE
     
    #include <iostream>
     
    using namespace std;
     
    class Foo
    {
     
    };
     
    #define OBJECT Foo*
     
     
    #ifdef WITH_TEMPLATE
    template<class T_Object>
    #else
    #define T_Object OBJECT
    #endif
    class Base
    {
    	public:
    	virtual bool method(const T_Object& obj)
    	{
    		cout << "Base: method" << endl;
    	}
    };
     
    #ifdef WITH_TEMPLATE
    class Child : public Base<OBJECT>
    #else
    class Child : public Base
    #endif
    {
    	public:
    	bool method(const OBJECT& obj)
    	{
    		cout << "Child: method" << endl;
    	}
    };
     
    int main(int argc, char** argv)
    {
    #ifdef WITH_TEMPLATE
    	Base<OBJECT> *b;
    #else
    	Base *b;
    #endif
    	OBJECT f;
    	Child c;
     
    	b = &c;
    	b->method(f);
     
    	return 0;
    }
    Merci d'avance.

  2. #2
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Mettre const en tete est trompeur.

    const Foo*, c'est Foo const*.

    Si T est un typedef sur Foo* ou un parametre template instancie avec Foo*, const T, c'est
    T const et donc Foo * const.

    Les parametres des fonctions membres ne sont donc pas les memes dans le cas du template et la deuxieme ne supplante pas la premiere.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 5
    Par défaut
    Merci Jean-Marc

    Le problème venait "tout simplement" de là. En remplaçant les "const T_Object&" par "T_Object const &", tout marche comme attendu.

    Merci beaucoup en tout cas pour avoir résolu mon problème ;-)
    Rien à dire d'autre à part réponse claire, rapide et efficace !

  4. #4
    Membre chevronné
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Par défaut
    La correction est à moitié correcte, cependant je ne suis pas d'accord avec l'avis de Jean-Marc là dessus.

    En effet, ce n'est pas un typedef mais un #DEFINE, la méthode dérivée est donc bien celle qui remplace la méthode mère, qui prennent tous 2 un Foo const * & comme paramètre.

    Cependant, tu leur passe Foo* comme paramètre qui est fondamentalement différent de Foo const *, mais qui est cast-able implicitement vers Foo* const.

    En modifiant donc comme tu l'as fait les méthodes, ça passe. Mais il ne faut pas oublier que Foo sera alors modifiable via le pointeur.

    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
     
    class Foo
    {
    public:
    	int a;
    };
     
    ...
     
    #ifdef WITH_TEMPLATE
    class Child : public Base<OBJECT>
    #else
    class Child : public Base
    #endif
    {
    	public:
    	bool method( OBJECT const & obj)
    	{
    		cout << "Child: method" << endl;
    		obj->a = 123; // !! Ca compile !!
    		return false;
    	}
    };
    Pour être sûr que ça ne soit pas modifiable, tes prototypes doivent être:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    virtual bool method(const T_Object const & obj)
    Ce qui revient à écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    virtual bool method(Foo const *const & obj)
    Qui équivaut donc une référence vers un pointeur constant sur un objet constant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #ifdef WITH_TEMPLATE
    class Child : public Base<OBJECT>
    #else
    class Child : public Base
    #endif
    {
    	public:
    	bool method( const OBJECT const & obj)
    	{
    		cout << "Child: method" << endl;
    		obj->a = 123; // !! Ca compile plus !!
    		return false;
    	}
    };

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 5
    Par défaut
    Merci pour ces précisions.

    Mais pas d'inquiétude, j'avais bien en tête que mes objets pointés étaient bien modifiables avec mes prototypes actuels...

  6. #6
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    La correction est à moitié correcte,
    Mettre const après fait fonctionner le code tel que présenté. Passer Foo const* en paramètre template de Base ainsi que modifier le prototype en method(T_Object&) aurait permit de supplanter mais pas de faire l'appel dans main. Ajouter des const partout permet aussi de faire fonctionner l'ensemble. Savoir ce qui est la bonne solution demande une connaissance du contexte qui ne nous est pas donnée.

    cependant je ne suis pas d'accord avec l'avis de Jean-Marc là dessus.
    Je reste sur mon avis sur la cause du problème.

    En effet, ce n'est pas un typedef mais un #DEFINE, la méthode dérivée est donc bien celle qui remplace la méthode mère, qui prennent tous 2 un Foo const * & comme paramètre.
    Je n'ai jamais dit qu'on se trouvait dans le cas du typedef, on est dans le cas du paramètre template.

    Sans #define WITH_TEMPLATE, on a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    bool Base::method(const Foo*& obj);
    bool Child::method(const Foo*& obj);
    On supplante bien.

    Avec, on a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<class T_Object> bool Base<T_Object>::method(const T_Object& obj);
    bool Child::method(const Foo*& obj);
    et Base est instantié avec T_Object qui vaut Foo*. Pour supplanter le membre virtuel (et non pas simplement le masquer), il aurait fallu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    bool Child::method(Foo* const& obj);
    Quant au deuxième point qui posait problème. Le code tente de passer à Base::method un Foo*. Avec la base templatée attend un Foo* const&, la référence est constante, pas de problème. La base non templatée attend un Foo const*&, ça ne passe pas pour la même raison qu'on ne peut pas assigner un Foo** à un Foo const**:
    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
     
    const Foo* global;
     
    void f(const Foo*& obj)
    {
       obj = global;
    }
     
    int main()
    {
       global = new Foo;
       Foo* ptr;
       f(ptr);
       *ptr = Foo(); // Ops, modifie *global
    }

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

Discussions similaires

  1. [C#] Information sur héritage et polymorphisme
    Par LE NEINDRE dans le forum C#
    Réponses: 21
    Dernier message: 14/06/2007, 11h00
  2. Réponses: 19
    Dernier message: 05/06/2007, 08h13
  3. Templates + Héritage + Allocation dynamique
    Par bouba dans le forum C++
    Réponses: 2
    Dernier message: 26/04/2007, 17h56
  4. Template, héritage multiple et redéfinition
    Par Paul Atreide dans le forum Langage
    Réponses: 5
    Dernier message: 31/10/2006, 14h00
  5. template, héritage et std:deque
    Par jmtrivial dans le forum Langage
    Réponses: 7
    Dernier message: 27/09/2006, 15h08

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