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 :

class friend et héritage


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut class friend et héritage
    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
    struct C_Base
    {
    private:
     ...
    public:
     ...
     virtual void M()=0;//all overloaded M() should access private members of Autre
    };
     
    struct C_Derive1: C_Base
    {
    private:
     ...
    public:
     ...
     virtual void M();//need to access private members of Autre
    };
     
    struct Autre
    {
     friend struct C_Base;
    private:
     ...
    public:
     ...
    };
    Je souhaiterais qu'une classe de base, et toutes ses dérivées, soient "friend" d'une Autre classe. Mais je voudrais éviter d'avoir à spécifier la liste des classes dérivées à Autre.
    Une solution à cela ?
    Merci.

  2. #2
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Pas de solution simple à ma connaissance, c'est une limitation de friend.

    Il y a peut-être un moyen de bricoler à base de friend template, en définissant tes classes dérivées comme spécialisation d'un type template. Je déconseille très fortement d'en arriver à une telle solution .

    Expose un peu plus en détail pourquoi tu aurais besoin de faire ça, et dans ce cas, on pourra t'orienter vers une solution plus propre (certains vont te dire que dès qu'il y a friend, ce n'est pas propre, personnellement, je ne partage pas du tout cet avis).

  3. #3
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Ca me semble difficile vu que l'amitié n'est ni héritée, ni transitive ou réciproque.

    Edit: +1 pour expliciter les besoins, ca sent la mauvaise conception.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  4. #4
    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,

    Ceci dit, toute fonction définie au sein de cette classe et non redéfinie dans les classes dérivées (donc a priori, les fonctions non virtuelles, et, pour qu'elles soient accessibles depuis les classes dérivées, déclarées publique ou protégées) sont réputé etre... de la classe de base...

    Aussi, si tu déclare la classe de base amie de ta classe Autre, et que tu définis les fonctions qui vont "profiter" de l'amitié dans la classe de base de manière non virtuelle et publique ou protégées (mais pas privée), tu pourra invoquer ces fonctions depuis les autres fonctions des classes dérivées
    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

  5. #5
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    J'explique, en espérant me faire comprendre, sans rentrer dans de longs et fastidieux détails

    J'ai une db SQL avec plein de tables. Rien de bien excitant, sauf qu'une de ces tables est du genre fourre-tout. Elle contient 3 champs principaux: "type", "subtype" et "data". En fait, le propriétaire des données, chaque fois qu'il a besoin de créer un contenu "secondaire" dans sa db, au lieu de créer une table (tâche sous-traitée et donc fastidieuse et coûteuse) il remplit cette table en créant un nouveau type. En gros il crée lui-même dynamiquement des "tables", le nom de la (fausse) "table" se trouve dans "type", les champs dans "subtype", et l'info correspondante dans "data".
    En fait il me semble que ce soit assez classique comme modèle fourre-tout.

    Pour gérer le contenu de cette table j'ai écrit une classe C++ qui l'encapsule.
    Mais comme les choses ne sont jamais simples, il y a de nombreux cas d'exception dans le traitement des données qui sortent du cas générique. J'ai donc créé une classe de base pour gérer le cas générique, classe amie de la classe d'encapsulation principale, puis au fur et à mesure de l'enrichissement du contenu, je crée une classe dérivée lorsque ce contenu sort du cadre générique. La classe de base et les classes dérivées doivent accéder à certaines infos privées de la classe d'encapsulation principale.

    Je pourrais déplacer de private vers public les champs nécessaires, mais seule la liste des classes dérivées peuvent y accéder.
    Donc pour l'instant chaque classe dérivée créée est aussi ajoutée dans la liste des classes friend. Bah, c'est pas bien grave, mais ça me fait bizarre.

    Si vous avez d'autres idées, merci

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Tu pourrais donner à ta classe d'encapsulation deux interfaces, une qui ne contient que les fonctions publiques, et que tu donnes à tes clients standards, et une autre contenant les fonctions de manipulation avancées (qui sont actuellement en privé dans ta classe), mais que tu ne passe qu'à ta hiérarchie de classe de manipulation.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class MonEncapsulation : public InterfacePublique, public InterfacePrivée {...}
    Ou une variante, mais encapsule moins, mais demande une classe de moins, et évite l'héritage multiple (certains sont peu à l'aise avec) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class MonEncapsulation : public InterfacePublique
    {
      // Et là, tu mets tout en public:
    }
    Tu dois aussi pouvoir fonctionner par composition, la classe englobante étant fournier publiquement, et contenant un pimpl vers une classe dont le .h n'est pas fourni au client de la classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MonImplementationOuToutEstPublique;
    class InterfacePublique
    {
      scoped_ptr<MonImplementationOuToutEstPublique> monImplementation;
    }
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Merci pour vos réponses.

    Etant dans un contexte de maintenance, il est difficile de tout chambouler. L'idée de koala01 me semble la plus simple et la plus adaptée.
    Et après réflexion, je pense que c'est une solution générale qui peut s'appliquer dans de nombreux contextes: confier à la classe de base l'essentiel des accès extérieurs.

    Encore merci.

  8. #8
    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
    Citation Envoyé par camboui Voir le message
    Merci pour vos réponses.

    Etant dans un contexte de maintenance, il est difficile de tout chambouler. L'idée de koala01 me semble la plus simple et la plus adaptée.
    Et après réflexion, je pense que c'est une solution générale qui peut s'appliquer dans de nombreux contextes: confier à la classe de base l'essentiel des accès extérieurs.

    Encore merci.
    Il faut quand même avouer que, si ma solution est valide et "correcte" (dans le sens où elle permet de faire ce que tu recherche), elle n'est malgré tout qu'un "pis allez" te permettant de résoudre un problème de conception à la base, car les réflexions à avoir sont:

    La (les) fonctions que tu t'apprête à rajouter à la classe de base sont, certes, utiles, mais sont-elles opportunes dans la classe de base

    D'une manière ou d'une autre, les fonctions rajoutées à la classe de base devront "communiquer" avec la classe dans laquelle tu déclare l'amitié.

    Cela implique, au minimum de passer cette classe par argument à la (aux) fonction(s) membre(s) rajoutée(s), au maximum de prévoir une composition ou une agrégation de cette classe dans la classe de base... Mais est-ce opportun
    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

  9. #9
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Il est difficile de prévoir les évolutions d'un projet dans le temps. Et dans ce cadre il est trop facile de remettre en cause une ancienne conception mais qui a pourtant permis de faire vivre de nombreuses personnes

    Pour en revenir à mon cas précis, les exceptions dont je parlais étaient gérées avec des if else if else if... Ça devenait un peu un plat de nouilles avec le temps. Je cherche simplement à donner plus de lisibilité à un code assez localisé sans tout revoir.

    Mais tu me fais penser à des cas magnifiques du monde des télécoms. Un central téléphonique c'est fait pour gérer des communications. En temps réel bien sûr. On est d'accord, pas de problème conceptuel là-dedans ?
    A l'époque, la solvabilité ou la fidélité d'un client n'était pas du ressort du central proprement dit. Puis un jour vinrent les équipes de marketing et leur imagination débordante avec pleins de choses à faire faire en temps réel... En bref, il y aura toujours un décalage "conceptuel" entre les équipes techniques et les vendeurs

  10. #10
    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
    Je suis bien conscient qu'il est parfois difficile de préjuger de l'évolution des besoins sur des délais finalement très long (20 ans, en IT, c'est une éternité)

    Mais il faut aussi parfois prendre conscience que l'on ne peut adapter l'ancien que "dans une certaine mesure", et qu'à un moment donné, il va sans doute falloir reprendre une bonne partie de la conception (utiliser éventuellement une base de donnée existante, mais revoir la manière dont elle est utilisée au final )

    Et je reste persuadé que la personne la mieux placée pour dire qu'il est peut être temps de passer "à une autre approche", c'est celle qui a en charge la maintenance de l'application...

    Quelque part, si tu ne signale pas aux responsables non informatiques que tu as atteint les limites de ce que tu peux faire "avec l'ancien", il ne faut pas compter sur eux pour s'en rendre compte

    Évidemment, cela signifie de partir sur un projet important, nécessitant de reprendre l'analyse depuis le début, couteux en temps et en énergie personnelle...

    C'est donc, quelque part, ton role de signaler aux autres "bon, j'applique une rustine pour nous permettre de continuer à travailler en suivant les évolutions actuelles, mais il est grand temps de se remettre autour de la table afin de réfléchir de manière globale et intégrée à ce que pourrait être la prochaine version de notre logiciel"
    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

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Je vais être plus brutal que Koala : refactoring du code ne s'impose que si le coût du refactoring + risque + gain maintenance espéré < coût de maintenance actuel... Ce qui fait que souvent on préfère continuer à bricoler
    C'est souvent frustrant mais c'est la réalité du marché...
    Ca peut se 'vendre' en segmentant le refactoring en petite tranche au coût suffisamment réduit ou en intégrant dans le cadre d'une évolution un peu conséquente. Mais, en général, on ne peut pas tout changer d'un coup (ne serait-ce qu'à cause du risque).

  12. #12
    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
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Je vais être plus brutal que Koala : refactoring du code ne s'impose que si le coût du refactoring + risque + gain maintenance espéré < coût de maintenance actuel... Ce qui fait que souvent on préfère continuer à bricoler
    C'est souvent frustrant mais c'est la réalité du marché...
    Ca peut se 'vendre' en segmentant le refactoring en petite tranche au coût suffisamment réduit ou en intégrant dans le cadre d'une évolution un peu conséquente. Mais, en général, on ne peut pas tout changer d'un coup (ne serait-ce qu'à cause du risque).
    Tout à fait, mais, si tu (le tu ici est à prendre au sens du service informatique) ne signale pas que tu as atteint la limite des bricolages que le système peut supporter, les décideurs ne pourront jamais se pencher sérieusement sur le problème pour décider s'il faut envisager le refactoring ou s'il est préférable de continuer à bricoler...

    Quelque part, et je les comprend: Tant qu'on peut apporter les modifications souhaitées, pourquoi passer à autre chose

    [EDIT]Ce que je veux dire, c'est qu'il ne faut pas avoir peur d'aller présenter son point de vue et de défendre ses arguments, autrement, si le décideur n'a pas conscience que "ca ne va plus", comment pourrait il prendre les bonnes décision

    Après, il y a tout le problème de trouver les arguments "qui feront mouche"
    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

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

Discussions similaires

  1. Réponses: 17
    Dernier message: 27/08/2007, 18h35
  2. Foncteur, classes templates et héritage
    Par Floréal dans le forum C++
    Réponses: 8
    Dernier message: 17/06/2007, 21h56
  3. Réponses: 2
    Dernier message: 05/04/2007, 13h19
  4. Probleme avec les classes friends
    Par Kerwando dans le forum C++
    Réponses: 4
    Dernier message: 27/10/2006, 23h29
  5. classe friend vs fonctions globales vs ...
    Par khayyam90 dans le forum C++
    Réponses: 8
    Dernier message: 23/03/2006, 23h19

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