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 :

Héritage de template, problème d'accès aux membres protected


Sujet :

Langage C++

  1. #1
    Membre éclairé Avatar de MatRem
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    750
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 750
    Points : 693
    Points
    693
    Par défaut Héritage de template, problème d'accès aux membres protected
    Bonsoir,

    J'ai un petit problème avec une architecture à base de template.
    On dirait que je ne peut pas accéder aux membres protected, d'une classe de base dans une classe dérivée.

    J'ai grandement simplifié le code pour en arriver là:
    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <cstdlib>
    #include "B.h"
     
    int main(int argc, char * argv[])
    {
    	B<int> b;
    	return EXIT_SUCCESS;
    }

    Code A.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifndef _A_H
    #define _A_H
     
    template<typename T>
    class A
    {
    public:
    	virtual ~A();
    protected:
    	T var;
    };
     
    #include "A.tpp"
     
    #endif

    Code A.tpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template<typename T>
    A<T>::~A()
    {}

    Code B.h : 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
    #ifndef _B_H
    #define _B_H
     
    #include "A.h"
     
    template <typename T>
    class B : public A<T>
    {
    public:
    	B();
    	virtual ~B();
    };
     
    #include "B.tpp"
     
    #endif

    Code B.tpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<typename T>
    B<T>::B()
    {
    	var = 0; //Problème ici
    }
    
    template<typename T>
    B<T>::~B()
    {
    }

    J'utilise g++ 4.1.2 et j'ai ce message d'erreur:
    g++ -c -Wall -Werror -pedantic -pedantic-errors -O3 -std=c++98 main.cpp -o main.o
    B.tpp: In constructor ‘B<T>::B()’:
    B.tpp:4: error: ‘var’ was not declared in this scope
    make: *** [main.o] Erreur 1

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Essaye avec this->var, je crois que c'est nécessaire avec les classes templates (au moins avec gcc).

  3. #3
    Membre éclairé Avatar de MatRem
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    750
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 750
    Points : 693
    Points
    693
    Par défaut
    Merci .
    Effectivement ça fonctionne, c'est pas dans la norme ça?

    Ça m'amène à une autre question, existe-t-il un meilleur compilateur, multiplateforme et libre que g++?

  4. #4
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    Citation Envoyé par MatRem
    Merci .
    Effectivement ça fonctionne, c'est pas dans la norme ça?
    Je crois que oui.
    Vandervoode/Josuttis expliquent pourquoi dans leur bouquin "C++ templates" (9.4.2)

  5. #5
    Membre éclairé Avatar de MatRem
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    750
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 750
    Points : 693
    Points
    693
    Par défaut
    Ha ok, très bien. Laurent avait l'air de dire que c'était une spécificité de g++.
    J'ai honte de ne plus avoir eu confiance en g++

    Est ce que quelqu'un connaît l'intérêt de ce point? (je ne possède malheureusement pas l'ouvrage que tu sites).

    Sinon je vais regarder dans le Stroustrup s'il en fait mention.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    258
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 258
    Points : 307
    Points
    307
    Par défaut
    On trouve aussi une explication sur le site de gcc. L'idée est que une spécialisation de A peut être déclarée après la déclaration de B, être utilisée par B et ne pas déclarer ta variable. Le compilo ne regarde donc pas dans la classe de base, mais dans le namespace englobant.

  7. #7
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par MatRem
    Est ce que quelqu'un connaît l'intérêt de ce point? (je ne possède malheureusement pas l'ouvrage que tu sites).
    Le point en question est la recherche des noms en deux phases et est plus general que l'heritage de template.

    Il permet d'avoir une meilleure predictabilite (seuls les noms dépendant explicitement d'un paramètre template en dépendent et ils en dépendent toujours, quelle que soit la valeur du parametre), eviter des cas de comportements indefinis (sans la recherche des noms en deux phases, on peut arriver facilement a des cas ou pour une instantiation donnee, un nom qui n'est pas dependant -- et donc cherche uniquement dans le contexte de la definition du template -- est resolu de maniere differente dans les differents contextes d'instantiation) et permettre la detection d'erreur pour tout ce qui ne depend pas des parametres template quand on voit la definition plutot qu'attendre une instantiation.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    De plus, tu fais une hypothèse relativement hasardeuse en écrivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template<typename T>
    B<T>::B()
    {
    	var = 0; //Problème ici
    }
     
    template<typename T>
    B<T>::~B()
    {
    }
    Tu pars du principe que var sera d'office une valeur numérique mais, qu'en est il d'un code du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <string>
    class C
    {
        public:
            C(){}
            ~C(){}
           (...)
        private:
            std::string name;
            (...)
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #include "B.h"
    #include "C.h"
    int main(int argc, char * argv[])
    {
    	B<C> b;
    	return EXIT_SUCCESS;
    }


    Tu as différentes possibilités lorsque tu conçoit l'héritage d'une classe template, mais, si tu veux partir de l'hypothèse que la variable du type template est une variable numérique, il faut que tu aies indiqué la spécialisation du type au sein meme de la classe dans laquelle tu fais l'hypothèse

    Ca peut prendre une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class D:public A<int>
    {
    (...)
    };
    par exemple

  9. #9
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Points : 460
    Points
    460
    Par défaut
    Citation Envoyé par Laurent Gomila
    Essaye avec this->var, je crois que c'est nécessaire avec les classes templates (au moins avec gcc).
    Petite suggestion de ma part:
    C'est plus pratique de déclarer une bonne fois pour toutes la variable dans la classe dérivée avec 'using' qui est là popur ça, plutôt que d'utiliser le pointeur 'this' à chaque utilisation.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <typename T>
    class B : public A<T>
    {
      public:
         typedef A<T> base;
         using base::var;
     
    ...
    };

  10. #10
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    Citation Envoyé par Charlemagne
    Petite suggestion de ma part:
    C'est plus pratique de déclarer une bonne fois pour toutes la variable dans la classe dérivée avec 'using' qui est là popur ça, plutôt que d'utiliser le pointeur 'this' à chaque utilisation.
    Dans le livre que j'ai cité, il donne trois variations pour éviter les problèmes de template et name lookup.
    Le using dont tu parles est la deuxième qui (si mes souvenirs sont bons) à le désavantage de désactiver la "virtualité".
    Il y a une troisème variation que je ne me rappelle pas

  11. #11
    Membre éclairé Avatar de MatRem
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    750
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 750
    Points : 693
    Points
    693
    Par défaut
    Merci pour toutes ces précisions . On dirait qu'on rentre dans le "compliqué" du c++ là. Il va falloir que je me trouve un bouquin spécial template.

    pour koala: en effet j'avais un peu trop simplifié mon exemple, en fait var est initialisé avec un paramètre de type T du constructeur.

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par MatRem
    Merci pour toutes ces précisions . On dirait qu'on rentre dans le "compliqué" du c++ là. Il va falloir que je me trouve un bouquin spécial template.
    Je conseille fortement celui de Josuttis et van de Voorde.

  13. #13
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Points : 460
    Points
    460
    Par défaut
    Citation Envoyé par Hylvenir
    Dans le livre que j'ai cité, il donne trois variations pour éviter les problèmes de template et name lookup.
    Le using dont tu parles est la deuxième qui (si mes souvenirs sont bons) à le désavantage de désactiver la "virtualité".
    Il y a une troisème variation que je ne me rappelle pas
    Je comprends pas bien ce que tu entends par "désactiver la virtualité"? un petit exemple peut-être? en tout cas ça ne peut détruire la virtualité que pour les fonctions, ici c'est une variable.

    Si tu retrouves la 3ème possibilité, je suis curieux.

  14. #14
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    Alors, voilà à ce que j'ai compris
    variation 1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<typename T>
    struct Derived : public Base<T> {
     void fct() { this->basefield_ = 0; }
    };
    // le this permet de faire la résolution de nom à l'instantiation du template
    variation 2:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<typename T>
    struct Derived : public Base<T> {
     void fct() { Base<T>::basefield_ = 0; }
    };
    // il semble que le nom qualifié désactive les appels virtuels (l'aide des gurus
    // est la bienvenue sur ce point ;)
    variation 3 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template<typename T>
    struct Derived : public Base<T> {
     using Base<T>::basefield_;
     void fct() { basefield_ = 0; }
    };
    // il peut y avoir des soucis pour qualifier comme il faut en cas d'héritage
    // multiples
    "C++ Templates" - The complete guide.
    Vandevoorde/Josuttis.
    un "must-have" pour essayer de comprendre les templates.

  15. #15
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Points : 460
    Points
    460
    Par défaut
    Bon OK.
    La variation 2 est la syntaxe habituelle pour appeler la fonction voulue, et en ce sens ça "casse la virtualité" mais c'est bien l'effet voulu...
    En général on s'en sert pour appeler la fonction virtuelle à partir de la surcharge de cette même fonction virtuelle.

    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
    struct A
    {
      virtual void f() 
      {  
        // faire qqch 
      }
    };
    struct B : public A
    {
      virtual void f()
      {
        A::f();
        // faire qqch en plus
      }
    };
    'using' n'est qu'un raccourci pour éviter d'écrire "classe_de_base::" en permanence.

    C'est vrai que 'using' sert aussi mais plus rarement lors des héritages multiples (l'héritage multiple est rarement une bonne idée, à part parfois pour les interfaces...) pour lever l'ambiguïté si 2 fonctions/variables de classes mères ont le même nom.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct A1
    {
      int a;
    };
    struct A2
    {
      int a;
    };
    struct B : public A1, public A2
    {
      using A1::a; // si je ne précise rien alors utiliser A1::a
    ...
    };
    De toute façon la syntaxe "this->" ne saurait lever l'ambiguïté éventuelle, donc je préfère personnellement utiliser 'using' pour sa concision.

  16. #16
    Membre du Club
    Inscrit en
    Septembre 2003
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 49
    Points : 43
    Points
    43
    Par défaut
    Le probleme, ici, est liee au "name lookup" (desole je ne sais comment cela s'appelle en francais). En utilsant l'expression this->Var l'exprssion devient qualifée (Qualified_id) et donc uniquement la classe B et ces bases sont considerees. Par contre pour un identificateur non qualifie le "scope" (ca aussi, j'ignore le terme en francais) est pris en consideration et la si le compilo trouve une variable nommee va dans l'espace de la classe B il n'ira pas voir plus loin et tentera d'utilser cette var.
    desole si ce n'est pas tres claire. On me reproche tjrs de mal expliquer les choses.
    a+

  17. #17
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par adel_dz
    Le probleme, ici, est liee au "name lookup" (desole je ne sais comment cela s'appelle en francais). En utilsant l'expression this->Var l'exprssion devient qualifée (Qualified_id) et donc uniquement la classe B et ces bases sont considerees. Par contre pour un identificateur non qualifie le "scope" (ca aussi, j'ignore le terme en francais) est pris en consideration et la si le compilo trouve une variable nommee va dans l'espace de la classe B il n'ira pas voir plus loin et tentera d'utilser cette var.
    desole si ce n'est pas tres claire. On me reproche tjrs de mal expliquer les choses.
    a+
    Ce n'est pas clair du tout, au point que je ne sais pas si c'est correct ou pas. Pour les traductions:

    Name lookup -> recherche des noms
    Scope -> portée

Discussions similaires

  1. Réponses: 4
    Dernier message: 04/09/2008, 10h58
  2. Réponses: 16
    Dernier message: 07/02/2006, 14h19
  3. [Applet] problèmes d'accès aux images
    Par wwave dans le forum Interfaces Graphiques en Java
    Réponses: 18
    Dernier message: 16/09/2005, 14h42
  4. Heritage accès aux membres de bases
    Par MAGNUM_HEAD dans le forum C++
    Réponses: 1
    Dernier message: 16/11/2004, 16h41
  5. [TOMCAT] JSP problème d'accès aux méthodes d'une classes
    Par gunnm dans le forum Tomcat et TomEE
    Réponses: 3
    Dernier message: 22/05/2004, 14h02

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