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 :

Accéder à des membres statiques enfants depuis une classe parent


Sujet :

Langage C++

  1. #1
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut Accéder à des membres statiques enfants depuis une classe parent
    Bonjour,

    Je dois actuellement chercher à faire quelque chose qui me semble trivial mais qui ne doit pas coller avec les principes du c++ et de l'objet en général.

    Je souhaiterais que des méthodes statiques d'une classe parent puissent accéder à des membres statiques redéfinis des classes enfants.
    Soit le code suivant:
    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
     
    class base {
    	public: static const int CONST1 = 10;
     
    	static int test(void){
    		return CONST1;
    	}
    };
     
    class ext : public base {
    	public: static const int CONST1 = 123;
    };
     
    int main (int argc, char* argv[]){
       std::cout << base::test() << std::endl;
       std::cout << ext::test() << std::endl;
    }
    J'obtiens actuellement l'output suivant:
    10
    10
    Alors que je souhaiterais obtenir
    10
    123
    La différence se faisant sur l'appelant de la méthode test() statique.

    En PHP il existe les Late Static Bindings (LSB) qui permettent de résoudre différemment la portée suivant que l'on veuille s'adresser à la classe qui déclare la méthode ou celle qui l’appelle. Cela reste bien sur quelque chose de border line vu que les classes parent ne doivent normalement pas maitriser le contenu déclaré dans les classes enfant. Ici je ne fais que des redéfinitions.

    Je travaille sous VS2012 CTP de novembre 2012 et affectionne beaucoup C++11.

    Merci par avance pour vos lumière et bon week end.

  2. #2
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Bonjour,

    Une méthode static est plus ou moins équivalente à une fonction libre. C'est lié à une classe et non à une instance de classe, du coup pas de polymorphisme possible. (Impossible de déclarer une fonction static virtuelle)

    Dans les deux cas tu appelles test (qui est donc une fonction non virtuelle), donc le seul CONST1 que tu vois c'est celui de la classe de base.

    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
    class base { 
    	static int test(void){
    		return 10;
    	}
    };
     
    class ext : public base {
    	static int test(void){
    		return 123;
    	}
    };
     
    int main (int argc, char* argv[]){
       std::cout << base::test() << std::endl; // 10
       std::cout << ext::test() << std::endl; // 123
       return 0;
    }
    En fonction de tes besoins, quelque chose comme ça, peut être envisageable.
    Mais il faut bien se rendre compte qu'il n'y a pas de polymorphisme ici : c'est juste que la fonction test() de la classe dérivée cache celle de base.

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

    Informations professionnelles :
    Activité : aucun

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

    La réponse courte, tout d'abord: il est impossible d'accéder à quoi que ce soit d'une classe dérivée depuis une classe mère.

    La réponse longue ensuite:

    La classe mère ne connait strictement rien des classes qui en dérivent, tu ne peux donc absolument pas espérer accéder à quoi que ce soit qui soit spécifique à la classe dérivée depuis la classe mère.

    Si tu connais un objet comme étant du type de la classe mère mais que tu veux accéder à quelque chose de spécifique à la classe dérivée, tu dois:
    • soit essayer de faire en sorte de connaitre directement ton objet comme étant du type de la classe dérivée
    • soit utiliser le "double dispatch" (dont l'une des implémentations classique est le patron de conception "visiteur")


    Je reste à ta disposition pour toute information supplémentaire permettant de mieux comprendre ces réponses
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Bonsoir messieurs et merci pour vos réponses,

    Je prends donc note que ce que je souhaite faire n'est pas réalisable en l'état (et c'est bien dommage).

    A la base je pose cette question pour éviter des redéfinitions de méthodes quand une vingtaines de classes en étendes une seule de base.
    Il me semblait plus light de redéfinir une constante que de redéfinir une méthode qui permette d'y accéder (avec éventuellement un peu de traitement).

    Il faut donc ensuite que je gère ça avec le design pattern visiteur qui semble être motivé par les mêmes choses... ou changer tout simplement d'architecture.

    Je me souviens avoir attendu avec une certaine impatience la sortie de PHP5.3 pour voir l'arrivée de ces fonctionnements parce que ça amène tout de même quelque chose.
    Sauriez-vous quelles considérations théoriques sont derrières la non présence de ces principes dans l'OO elle-même?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Le principe de base de l'orienté objet est la substituabilité, c'est à dire le fait que l'on puisse "faire passer" un objet d'un type dérivé comme étant un objet de son type de base.

    Le principal principe à respecter pour assurer la substituabilité est le Principe de Substitution de Liskov (LSP de son petit nom en anglais )

    Il faut comprendre que n'importe qui peut décider de faire dériver une de ses classes personnelles d'une classe qui existe "par ailleurs" si LSP est respecté et qu'il est opportun pour lui d'envisager l'héritage (comprend: s'il estime en son âme et conscience que sa classe personnel peut bel et bien être comme "étant une spécialisation" de la classe de base envisagée, au sens sémantique du terme).

    Le problème, c'est que la personne qui décide de faire hériter une de ses classes personnelles d'une classe existante n'a peut être strictement rien à voir avec la personne qui a décidé de fournir la dite classe de base.

    Par exemple, si je te fournis une bibliothèque créée par moi, il n'y a strictement rien qui t'empêche de décider, dans le respect de LSP, de faire hériter une de tes classes d'une de celles que je te fournis dans ma bibliothèque.

    Comment veux tu donc que je puisse prévoir, d'une manière ou d'une autre, ce que tu mettras dans ta classe personnelle, étant entendu que si tu décides de le faire, c'est parce que les classes que ma bibliothèque te proposent ne correspondent pas tout à fait à ce dont tu as besoin

    De même, lorsque j'ai écrit ma belle bibliothèque, lorsque j'ai réfléchi à la classe de base, il y a de fortes chances que j'aie décidé de la créer parce qu'elle m'était utile à quelque chose.

    Mais, les besoins évoluant en permanence, il se peut très bien que je me sois moi-même trouvé confronté à un besoin que je n'avais pas, au départ, envisagé...

    Comment voudrais tu que je fasse, alors que je ne sais pas au moment de créer ma classe de base, pour prévoir un besoin spécifique de ma classe dérivée alors que je ne sais strictement pas quel pourrait être ce besoin au moment où j'implémente ma classe de base

    En outre, il faut comprendre le principe de l'héritage.

    Lorsque tu décide que B hérite de A, c'est parce que B EST UN A... Avec un "petit quelque chose de plus".

    Du coup, lorsque tu vas créer un B, tu vas commencer (en fait, c'est le constructeur qui s'en occupe ) par créer un A, puis tu vas "rajouter ce petit quelque chose de plus".

    De même, lorsque tu vas détruire ton B, tu vas commencer par détruire le "petit quelque chose de plus" qui fait que ton B n'est pas "tout à fait" un A, puis tu vas détruire ce qui fait ton A.

    Enfin, il faut aussi comprendre ce que sont les patrons de conception.

    Ce ne sont que des "recettes" dont on s'est rendu compte qu'elles étaient régulièrement utilisées, avec certaines variantes, quand les développeurs étaient confrontés à des problèmes relativement similaires.

    Ce n'est donc jamais que la "mise en forme" de pratiques que l'on rencontre régulièrement dans les différents projets

    Cela n'a strictement rien à voir avec les principes propres à l'OO et n'a absolument pas lieu d'y entrer (même s'il faut respecter les principes OO pour mettre les patrons de conception en oeuvre )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Il faut donc ensuite que je gère ça avec le design pattern visiteur qui semble être motivé par les mêmes choses... ou changer tout simplement d'architecture.

    Je me souviens avoir attendu avec une certaine impatience la sortie de PHP5.3 pour voir l'arrivée de ces fonctionnements parce que ça amène tout de même quelque chose.
    Sauriez-vous quelles considérations théoriques sont derrières la non présence de ces principes dans l'OO elle-même?
    Le pattern visiteur marche dans un contexte objet, mais la tu n'es pas dans un contexte objet :
    - les fonctions membres statiques ne sont rien d'autre que des fonctions libres camouflées
    - de même, les attributs statiques sont équivalents à des variables globales (avec un scope réduit).

    Il suffit de voir la ressemblance entre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    namespace Foo {
       int i;
       void bar() { }
    }
    // et
    struct Foo {
       static int i;
       static void bar() { }
    };
     
    // à l'utilisation on ne sait même pas si on appelle une fonction libre dans un namespace
    // ou une fonction static dans une classe, mais c'est pas grave, car ça ne change rien.
    Foo::bar();
    Foo::i = 12;

  7. #7
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Très bien, merci koala pour cette explication détaillée, as usual!

    Tu vas peut-être trouver que je joue sur les mots mais l'approche à laquelle je pensais ne me semble pas incompatible avec ton exposé.

    Ici je ne postule pas pour la présence dans les classes enfant d'éléments différents de ceux de la classe de base.
    Je ne fais que re-définir une constante qui existe déjà dans la classe de base, c'est déjà un cas qui restreint les possibilités.

    Je ne connais pas la cuisine interne qui permet au LSB PHP de fonctionner, néanmoins c'est mille fois moins contraignant que de devoir implémenter le DP Visteur sur mon architecture.
    Même si PHP ne respecte que très peu de principe OO finalement, je le concède.

    Iradrille, je suis tout à fait d'accord avec ton observation. J'ai l'impression par contre qu'elle ne va pas m'aider pour arriver à mes fins....

    Bref, j'ai l'impression d’être un peu contraint d'utiliser un truc assez raide pour arriver au même résultat ou rester bloquer

  8. #8
    Membre habitué
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Points : 176
    Points
    176
    Par défaut
    Salut.

    Avec un peu de CRTP et les type_traits C++2011 ça passe nickel :

    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
    #include <iostream>
    #include <type_traits>
     
    // Base class
    class base
    {
       public: static const int CONST1 = 10;
       static int test(void){
          return CONST1;
       }
    };
     
    // Crtp class
    template <class crtp = void>
    class intermediate : public base {
       public: 
       static int test(void){
          typedef typename std::conditional<std::is_void<crtp>::value, base, crtp>::type selection;
          return selection::CONST1;
    	}
    };
     
    // Examples
    class ext1 : public intermediate<ext1> {
    	public: static const int CONST1 = 123;
    };
    class ext2 : public intermediate<ext2> {
       public: static const int CONST1 = 456;
    };
    class ext3 : public intermediate<ext3> {
       public: static const int CONST1 = 789;
    };
     
    // Main
    int main (int argc, char* argv[]){
       std::cout << base::test() << std::endl;
       std::cout << intermediate<>::test() << std::endl;
       std::cout << ext1::test() << std::endl;
       std::cout << ext2::test() << std::endl;
       std::cout << ext3::test() << std::endl;
    }
    à moins que j'ai mal compris la philosophie de ce que tu cherchais à faire. Tu as quand même 2 fonctions test() à définir, mais ce nombre n'augmente pas avec le nombre de classes filles. Dis moi si c'était ce genre de chose que tu cherchais à faire .

    Le code est dispo ici : http://liveworkspace.org/code/2sYW00$20

  9. #9
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Bonsoir Kaluza et merci pour cette réponse salvatrice!

    Je n'ai pas encore testé ce code à fond mais il passe l'épreuve de la compilation chez moi.
    Décidément C++11 permet de sortir de pas mal d'embuches. Comment ils faisaient avant?

    problème résolu, code utilisé en l'état, au namespace près.

    Bonne soirée.

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Décidément C++11 permet de sortir de pas mal d'embuches. Comment ils faisaient avant?
    Avec Boost, voire, à la main.
    Mieux, on se débrouillait pour ne pas en avoir besoin
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    Membre habitué
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Points : 176
    Points
    176
    Par défaut
    Content que cela t'ai aidé. Le CRTP ça existait avant C++11 (encore un hack tordu à grand coup de template). Mais pour moi qui suis en train de développer une bibliothèque pour l'astro à grand renfort de métaprog, je peux te dire que le header type_traits a une valeur inestimable

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 19/07/2013, 04h28
  2. [WD17] poo : comportement des membres globaux (static) d'une classe
    Par lmontout dans le forum WinDev
    Réponses: 5
    Dernier message: 26/12/2012, 12h21
  3. Réponses: 2
    Dernier message: 18/09/2012, 14h58
  4. Réponses: 4
    Dernier message: 27/07/2007, 18h18
  5. [C#] Accéder à un control depuis une class
    Par choas dans le forum Windows Forms
    Réponses: 4
    Dernier message: 02/05/2006, 13h43

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