L'héritage privé est notre ami (maintenant que nous discutons de cela sur le forum C++)
L'héritage privé est notre ami (maintenant que nous discutons de cela sur le forum C++)
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
L'impulsion qui nous pousse à prendre une méthode init() s'inscrit dans le besoin de rassembler toutes les variables (ie conditions initiales) dans un bloc qu'on repère rapidement en mode visuel. J'aurais presque envi de parler de "rubrique" initialisation dans la méthode constructeur de la classe si on voudrait être propre en terme d'indentation.
Il me semble que B. Meyer utilise des préconditions et postconditions dans le langage Eiffel.
Le principal interêt que je trouve dans la programmation objet réside dans l'organisation des données et des méthodes par rapport à une logique métier (ie classe) plus en phase avec le discours des utilisateurs.
UML va dans ce sens, et la programmation objet de part sa structuration offre une compatibilité très bien adapté pour aborder le métier. Il faut peut être pas oublié que ce sont les travaux fait sur la programmation objet qui ont conduit à l'élaboration d'UML.
Par objet immutable, faut-il comprendre que l'objet ne change plus après la création où qu'ils respectent le comportement de la classe. Autrement dit, pour l'héritage privé comme les méthodes qui modifient les dimensions ne sont plus public, donc plus accessibles, donc plus modifiables, sont accédés une seul fois et utilisent les variables transmisent au constructeur de la classe, quand l'objet est instancié.
Utiliser l'héritage privée voudrait dire qu'on contourne LSP, du moins on ne l'utilise pas ?
Justement, LSP introduit un cadre de travail par l'utilisation de contrat, préconditions et postconditions de telle sorte que:On peut objecter: "Quand on travaille avec des références ou des pointeurs, le polymorphisme peut faire qu'on ne sait pas si on travaille avec un rectangle ou un carré"
Une phrase tirée de cette page Le principe de substitution de LiskovUne fonction qui utilise un objet d'une classe mère doit pouvoir utiliser toute instance d'une classe dérivée sans avoir à le savoir.
Une donnée peut être immuable dans un contexte (particulièrement en C++). Cela veut dire que son état ne peut pas être altéré dans ce contexte. Si on dit juste qu'une donnée est immuable, cela veut dire qu'elle n'est pas altérable passé sa construction.
L'héritage privé du C++, vu qu'il ne réexporte pas les membres de la classe, la syntaxe du langage fait que les objets enfants ne peuvent pas être substitués en place d'un objet parent. La syntaxe ne permettant aucune substitution possible, on n'entre pas dans le cadre où le LSP a un quelconque sens -- le LSP demandant qu'en cas de substitution que tous les contrats soient bien scrupuleusement respectés, là la substitution n'est syntaxiquement pas possible.
Les fonctions init() ne sont qu'un résidu de vieilles méthodes d'apprentissage où l'on passe d'une fonction libre init() initialisant une structure à une fonction membre init() à un constructeur. Du coup, ceux qui se sont arrétés en cours de route peuvent penser que cette fonction membre est valide. Alors qu'en fait elle ne fait que permettre l'existence d'objets partiellement construits dont on ne peut rien faire : soit des objets avec des invariants trop laxistes. En abusant de ce cheminement de pensée (d'invariants trop laxistes), j'en suis arrivé à dénigrer les constructeurs par défaut, tout particulièrement dans le cadre des entités et des données que l'on pourraient avoir immuables plutôt que partiellement construites.
NB: il arrive que l'on ait un besoin d'une fonction init() virtuelle terminant une construction de façon polymorphique, mais là c'est une autre histoire : il faudrait la laisser protégée avec le constructeur, et fournir une fonction factory qui s'occupe appeler le bon constructeur avec la fonction de post-construction derrière.
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Ok, comme les membres sont privés, donc pas publiques, on ne peut appliquer LSP puisque ces membres sont inaccessibles dans une fonction qui manipulerait la référence de l'objet. LSP n'a aucun sens, donc il faut aussi tenir compte de l'accessibilité des membres (ie privée, protégé et publique).
Non.
A partir du moment où la syntaxe offre la substituabilité, il faut blinder en s'assurant que le LSP est respecté. Quand la syntaxe ne l'offre pas, on n'a pas à s'en inquiéter.
Le C++ offre un héritage dépourvu de substituabilité syntaxique: l'héritage privé. Ruby a un truc qui ressemble je crois. Java en est totalement dépourvu, il n'a que la composition/délégation.
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
J'ai confondu avec membres privé, je ne connaissais pas cette forme d'héritage.Le C++ offre un héritage dépourvu de substituabilité syntaxique: l'héritage privé
Réutiliser la fonction du calcul d'aire du rectangle pour un carré c'est tout l'intérêt du truc.
Avec des interfaces/classes (en syntaxe Java-like verbeuse, moche et nulle) :
Et voilà, la fonction qui calcule l'aire marche aussi bien pour AlignedSquareImpl que pour AlignedRectangleImpl, ce qui est fort utile.
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 interface AlignedRectangle { double get_posx(); double get_posy(); double get_height(); double get_width(); } interface AlignedSquare extends AlignedRectangle { } class AlignedRectangleImpl implements AlignedRectangle { private double posx; private double posy; private .... .... les accesseurs et les constructeurs } class AlignedSquareImpl implements AlignedSquare { ... même chose que AlignedRectangleImpl sauf que height == width, donc y a moins à stocker } double area(AlignedRectangle r) { return r.get_width() * r.get_height(); }
Définir un rectangle non aligné après c'est plus variable. Il me semble qu'en général on fait un rectangle aligné avec un angle d'orientation, donc du coup on peut réutiliser la largeur et la hauteur.
Un bon candidat pour la composition, mais certainement pas pour l'héritage.
Après avoir découvert LSP, je trouve que c'est un bon moyen pour élaborer des test unitaires. Je dirais que ça donne une idée plus claire pour faire des test unitaires tout au moins pour la partie héritage.
Un certain nombre de développeurs seraient tentés d'utiliser l'héritage pour éviter de réécrire du code. En intégrant LSP dans les tests unitaire à condition des les utiliser bien entendu, c'est se donner les moyens d'éviter ce genre de désagrément ou de comportement.
Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
Est ce que l'héritage privé est une pratique courante, parce c'est tout de même une particularité dans C++ comme l'héritage multiple.
Ce que je n'arrive pas à comprendre, pourquoi la plupart des langages supportent que l'héritage simple, qu'ils ont pas d'héritage privé.
Est ce que c'est de la bidouille (c'est de la provoc!), pourquoi les langages objets n'ont-ils pas tous les mêmes possiblités alors qu'on parle de paradigmes objets.
Est ce qu'on peu aussi utilisé LSP pour les héritages multiples ?
Le C et le C++ ont toujours eu la politique de "ne pas faire payer quelque chose que tu n'utilise pas" et de "ne pas placer plus de limitations que nécessaire".
C'est, notamment, la raison pour laquelle tout ne dérive pas automatiquement d'une classe de base commune (Object), que les méthodes des classes ne sont pas automatiquement virtuelles ou encore que l'héritage n'est pas automattiquement virtuel.
En cela, le C++ ne fait, en définitive, que d'accepter que l'on implémente strictement ce qui a été représenté en phase d'analyse et de conception (UML, par exemple, n'éprouve aucun problème avec l'héritage multiple)
Par contre, d'autres langages ont d'autres points de vue (qu'il faut aussi accepter et tenter de comprendre) qui se basent pour la plupart sur "il est potentiellement dangereux de..." et qui, pour éviter tout risque et en accord avec leur specs, préfèrent interdire ce qui est "potentiellement dangereux".
Comme tout n'est jamaiis tout blanc ou tout noir, il faut se dire que, de toutes manières, ce que l'on gagne d'un coté se perd très facilement de l'autre:
Le point de vue du C et du C++ permet une plus grande "adaptibilité" aux besoins réels, mais laisse également le champs libre au fait de se planter si l'on n'y prend pas garde
Le point de vue des autres langages est, quelque part, plus sécuritaire, mais c'est au prix d'une moins grande liberté dans ce que l'on fait, voire, de la nécessiter de contourner les limitations imposées quand elles vont à l'encontre de nos besoins réels (la notion "implements" de Java en est un exemple)
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
Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
Donc l'héritage privé en C++ autorise une souplesse tout en étant conforme aux "règles de conception". Pour les langages plus "sécurisés", on a pas d'autre choix que de passer par la composition/délégation.
C'est la raison d'être du garbage collector. Je voulais porter une appli PC sur un serveur. On m'empêchait de le faire sous prétexte que la mémoire devait être contrôlée, donc soit plateforme Java ou .NET. On pourrait presque dire que ces langages sont stratégiques car sans GC, ils n'ont pas le droit de cité sur les serveurs en dehors de langages natifs (ie sans pointeurs) dont les ressources sont entièrement gérées par l'OS (ie secure). C'est le message qu'on a voulu me faire passer.Par contre, d'autres langages ont d'autres points de vue (qu'il faut aussi accepter et tenter de comprendre) qui se basent pour la plupart sur "il est potentiellement dangereux de..." et qui, pour éviter tout risque et en accord avec leur specs, préfèrent interdire ce qui est "potentiellement dangereux".
Je sais, cette phrase devrait être sur un autre post, mais la permissivité du langage C++ et ce n'est pas le seul (ie pas de GC) fait que les langages objets non "secure" n'ont pas le vent en poupe. C'est un avis critiquable![]()
Le fait est que l'informatique est sans doute le seul domaine ou le point de vue compte plus que la question que l'on se pose (ou que le problème auquel on est confronté), et ou l'on peut, sur base du point de vue adopté, trouver strictement tout et son contraire.
Celui qui veut de "l'absolu sécuritaire" doit absolument comprendre que cela se fera - d'une manière ou d'une autre - au dépend des "performances brutes" (je pense ici aux algorithmes d'autentification et de cryptage/décryptage qu'il faudra mettre en oeuvre et qui... prendront du temps bien plus qu'à autre chose), celui qui veut du "vite conçu" que cela risque d'entrer en contradiction avec la "pérénité" de l'application...
Il s'agit donc toujours de "déplacer le curseur" de telle manière à trouver le "juste compromis" entre des besoins qui sont parfois diamétralement opposés, et c'est ce qui fait que tous les langages restent plus ou moins utilisés, quitte à ce qu'ils ne le soient que dans certains "secteurs de niche".
Tu parles ici de C++ que tu compares (car il se trouve dans le même vocable) à C# et à java, mais sais tu qu'il y a encore, de par le monde, des millions de lignes de code COBOL ou Ada en exploitation au moment où j'écris ces lignesAs tu conscience qu'elles seront encore en exploitation bien après
![]()
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
a- Non, c'est très peu connu, et donc peu répandu.
b- Ce n'est pas la plupart des langages, essentiellement un qui a voulu simplifier les choses, et ceux qui s'en sont inspirés.
Eiffel supporte très bien l'héritage multiple -- je ne sais plus s'il dispose d'un héritage d'importation de code. Ruby supporte l'importation de code, indépendamment de l'héritage orienté substituabilité.
C'est bien une forme de bidouille. Disons un "sucre syntaxique" pour faire moins "provoc". Un sucre syntaxique qui toutefois offre certains avantages de l'héritage (la possibilité de supplanter des fonctions : d'avoir un cadre restreint et familial de substituabilité)
Après, chaque concepteur de langage fait ses propres choix.
d- A partir du moment où tu isoles bien les divers axes selon lesquels tu hérites (implémenter les contrats de A et B (-> LSP), importer le code de C, etc) l'héritage multiple se passe beaucoup mieux que si on ne prend pas un tant soit peu de recul. Maintenant, c'est très scolaire ce que je te dis. Savoir où tu vas va aider, mais tu peux tomber dans des cas particuliers où tu devras composer avec l'existant sans tout casser et refactorer.
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Dire que Java est un genre de C++, on serait tenté de parler d'héritage, mais comme Java ne supporte que l'héritage simple au lieu de l'héritage multiple on se retrouve dans le cas du carré et du rectangle, LSP est violé () donc la relation d'héritage ne fonctionne pas
Blague à part, après avoir jeté un coup d'oeil à la FAQ C++, j'ai les idées plus claires , j'y ai aussi trouvé les "friends", encore une particularité.
Est ce que l'héritage multiple est souvent utilisé en C++? Comme je le comprends, ce n'est pas parce qu'un langage offre des possibilités qu'on les exploite pour antant.
C'est pas courant courant mais ca arrive. Le cas typique ou je l'utilise
c'est quand je veux qu'un objet soit un observeur mais cette
caracteristique ne fait pas partie de son interface. L'autre cas est quand
il faut controler l'ordre d'initialisation et faire en sorte que ce dont on
herite de maniere privee soit construit avant une base.
En passant, l'heritage prive est relativement souvent associe avec un
heritage multiple (et l'autre base est publique).
L'heritage multiple une particularite du C++? Ca demande uneparce c'est tout de même une particularité dans C++ comme l'héritage
multiple.
justification. La notion d'interface est une forme restreinte d'heritage
multiple mais le point de vue selon lequel uniquement cette forme devrait
etre publique est un point de vue qui se tiendrait assez bien.
Quelle opposition veux-tu faire? simple/multiple ou public/prive.Ce que je n'arrive pas à comprendre, pourquoi la plupart des
langages supportent que l'héritage simple, qu'ils ont pas d'héritage
privé.
Dans le premier cas, le qualificatif "la plupart des langages" demande une
justification -- je n'ai pas fait de statistique en la matiere, c'est
peut-etre vrai mais peut-etre faux et il faut voir ou tu places les
interfaces. Dans le cas des langages au typage statique, tu as deux effets
qui peuvent expliquer: theorique -- une meilleure adequation avec un
systeme de type se combinant mal avec l'heritage multiple -- et pratique --
l'heritage multiple n'est pas si simple a implementer de maniere
performante.
Dans le second cas, on se trouve dans un autre axe de la conception. Il y
a d'autres choix possibles que de placer ce genre de protection sur les
classes. Voir Java (ou si je ne m'abuse pas, protected a un autre sens)
Ada (qui la place sur les packages -- avec dans les packages une relation
pere-fils) ou Modula-3 (qui a des revelations partielles -- qui permet de
presenter une interface differente a chaque client, ce qui est plus fin que
simplement public/protected/private).
Le fait que tu mettes paradigmes au pluriel donne la reponse (meme si ceEst ce que c'est de la bidouille (c'est de la provoc!), pourquoi les
langages objets n'ont-ils pas tous les mêmes possiblités alors qu'on parle
de paradigmes objets.
n'est pas volontaire). Il vaut aussi voir comment ca s'accorde avec
d'autres concepts, pas necessairement lies avec ce qu'on appelle l'oriente
objet.
Oui.Est ce qu'on peu aussi utilisé LSP pour les héritages multiples
?
Et a mon avis meme, contrairement a ce qui a ete dit, pour les heritages
prives. Le fait que l'heritage est prive indique simplement que le fait
que cette relation de sous-typage ne fait pas partie de l'interface, elle
est une caracteristique de l'implementation actuelle.
J'ai beaucoup de mal a voir le rapport entre les deux. En fait, l'heritage
prive me semble un moyen de documenter un invariant et d'imposer qu'il soit
respecte.
Le plus grand tord des GC, c'est qu'ils sont vendus pour ce qu'ils ne sontC'est la raison d'être du garbage collector. Je voulais porter une
appli PC sur un serveur. On m'empêchait de le faire sous prétexte que la
mémoire devait être contrôlée, donc soit plateforme Java ou .NET. On
pourrait presque dire que ces langages sont stratégiques car sans GC, ils
n'ont pas le droit de cité sur les serveurs en dehors de langages natifs
(ie sans pointeurs) dont les ressources sont entièrement gérées par l'OS
(ie secure). C'est le message qu'on a voulu me faire passer.
pas: une maniere d'eviter de concevoir la gestion de la memoire (ils sont
un moyen de faciliter l'implementation d'une serie de politiques de gestion
de la memoire, il faut encore verifier que c'est bien une d'entre elles
qu'ils faut utiliser, et pour la plupart il faut aussi agir sur le code).
Partager