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 :

Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?


Sujet :

Langage C++

  1. #141
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Si elle est non mutable, ca ne me gene pas, si elle l'est, ca me gene vraisemblablement (ca va dependre des aspects mutables).
    C'est justement la question que je pose, parce que je ne comprend pas bien le point de vue de koala01.

    Si on caractérise les objets par leurs types, le LSP "comportemental" est encore plus nécessaire. Comme le dis Jean-Marc, il faut absolument que les instances des objets (base ou dérivés) conservent les propriétés qui caractérisent leur type.

    Le seul fait "d'être capable de réagir à l'appel de la dite fonction" (dixit koala01) - ce que je traduis par être "castable" - est loin d'être suffisant pour garantir qu'on maintient la cohérence de la modélisation.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  2. #142
    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 pseudocode Voir le message
    ? Ca ne contredit pas ma remarque.

    - Un rectangle est un quadrilatère dont les quatre angles sont des angles droits.
    - Un carré possède les mêmes propriétés qu'un rectangle

    Tu sembles donc d'accord pour dire qu'on peut donc définir une classe "Carré" qui hérite de la classe "Rectangle". Non ?
    Attention...

    Je dis que la programmation par contrat n'est pas forcément applicable, et que LSP doit malgré tout être respecté malgré le fait que, dans certaines circonstances, la programmation par contrat ne soit pas appliquée, et indépendamment des règles que ce type de programmation peut imposer.

    Tu sembles oublier que je plaide pour le fait de se poser quatre questions distinctes si elles sont opportunes, dont la dernière, qui enlèvera la décision si elle est d'actualité, consiste à s'assurer que les règles imposées par le style de programmation envisagé seront respectées

    Dans le cas d'une relation d'héritage entre carré et rectangle, LSP est, dés le départ, violé parce qu'il n'y a pas plus de sens à accepter l'idée de demander la longueur ou la largeur d'un carré que d'accepter celle de demander la taille du côté d'un rectangle, étant donné l'ambigüité qui existe face à cette dernière demande: Carré et rectangle partagent un certain nombre de propriétés qui leur viennent de... quadrilatère ou de parallélogramme, mais on ne retrouve aucune propriété propre à carré (respectivement à rectangle) dans rectangle (respectivement carré).

    Ensuite, on se rend effectivement compte que la programmation par contrat s'avère être une aide efficace pour nous éviter de faire des boulettes, et que, dans le cas que tu exposes, nous serions bien inspirés de la mettre en oeuvre.

    Si tant est que l'on ait commis l'erreur d'accepter l'éventualité de l'héritage au moment où l'on s'est assuré du respect de LSP, le "style de programmation", connu ici sous le terme de "programmation par contrat" nous servira de "garde fou".


    En effet, si la question du respect de LSP nous a donné "l'accord de principe" pour l'héritage, la question de savoir si on respecte les règles de la programmation par contrat nous fera remarquer que nous faisons fausse route.

    Mais nous ne devons nous poser ce genre de question que parce que nous sommes effectivement dans un contexte où nous devons assurer un certains nombre de conditions et le respect d'un certains nombre de règles définies "par ailleurs" (dans le cas qui nous occupe: dans les règles de la géométrie) aux différents types que l'on envisage de créer (telle que celle qui dit que les quatre cotés d'un carré doivent être égaux).

    Quelque part, le raisonnement que tu nous montre est typique du type "un peu trop pressé" qui tire "des conclusions hâtives", sans s'être posé les *bonnes* question (et surtout sans avoir réfléchi *correctement* aux réponses qu'il fournit à ces questions )

    Le fait est que LSP est un principe de conception d'ordre tout à fait générale, qui doit être pris en compte, que l'on envisage la programmation par contrat ou non, et que la programmation par contrat est un "style de programmation" destiné à s'appliquer à des circonstances particulières, à évaluer "bien après" avoir évaluer la mesure dans laquelle on respecte LSP ou non.
    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

  3. #143
    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 pseudocode Voir le message
    C'est justement la question que je pose, parce que je ne comprend pas bien le point de vue de koala01.

    Si on caractérise les objets par leurs types, le LSP "comportemental" est encore plus nécessaire. Comme le dis Jean-Marc, il faut absolument que les instances des objets (base ou dérivés) conservent les propriétés qui caractérisent leur type.

    Le seul fait "d'être capable de réagir à l'appel de la dite fonction" (dixit koala01) - ce que je traduis par être "castable" - est loin d'être suffisant pour garantir qu'on maintient la cohérence de la modélisation.
    Je n'ai jamais parlé de "être castable", j'ai parlé de la nécessité pour chaque type dérivé d'exposer "publiquement" au minimum ce que le type de base expose publiquement.

    Car, indépendamment du langage, si tu interdit à une instance du type dérivé d'invoquer une fonction publique du type de base, il faut bien constater que la propriété que l'on pourrait nommer "etre capable d'invoquer la fonction machin", valide pour le type de base, est invalide pour le type dérivé.
    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. #144
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je n'ai jamais parlé de "être castable", j'ai parlé de la nécessité pour chaque type dérivé d'exposer "publiquement" au minimum ce que le type de base expose publiquement.
    Je ne vois pas la différence...

    En terme d'implémentation, le mécanisme d'héritage du langage nous garantit que ce sera le cas : une classe dérivée exposera au moins les mêmes attributs/méthodes que la classe de base. (au problème près de la question posée sur l'accessibilité )

    Pour autant rien ne garantit le LSP, à savoir que la classe dérivée expose les memes propriétés qui caractérisent le type (ou le comportement).

    A moins que tu ne fasses la simplification "type" = "attributs/méthodes exposés" ?
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  5. #145
    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 pseudocode Voir le message
    Je ne vois pas la différence...
    La différence tient dans le fait que le transtypage n'est qu'une méthode de conversion d'un type en un autre, et que cette méthode peut parfaitement s'effectuer sans qu'il n'y ait la moindre relation d'héritage entre les deux types envisagés.

    Lorsque tu écris un opérateur de conversion de const char* en std::string (ou en n'importe quel autre type de ton cru), tu réalise effectivement un transtypage, car tu obtiens au final un type différent du type d'origine.

    Et pourtant, tu n'as absolument aucune relation d'héritage
    En terme d'implémentation, le mécanisme d'héritage du langage nous garantit que ce sera le cas : une classe dérivée exposera au moins les mêmes attributs/méthodes que la classe de base. (au problème près de la question posée sur l'accessibilité )
    C'est, justement, parce que le mécanisme d'héritage nous garanti que ce sera le cas que tu dois veiller à ce que ce soit effectivement ce à quoi tu t'attend.

    LSP est "simplement" là pour te permettre de réaliser que c'est effectivement le cas et que c'est une absolue nécessité.

    Si tu en viens, dans un type dérivé, à restreindre l'accessibilité d'une fonction déclarée comme "accessible depuis l'extérieur" dans le type de base, tu va simplement à l'encontre de cette règle primordiale, et LSP te permet d'en prendre conscience parce que, une fois que tu as une instance du type dérivé, tu ne peux pas envisager d'appeler une fonction que tu es pourtant habilité à appeler depuis le type de base.
    Pour autant rien ne garantit le LSP, à savoir que la classe dérivée expose les memes propriétés qui caractérisent le type (ou le comportement).
    Justement, LSP garanti que les propriétés exposées par le type de base seront exposées par le type dérivé... C'est le fondement même de son énoncé.
    A moins que tu ne fasses la simplification "type" = "attributs/méthodes exposés" ?
    Je ne fais aucune simplification, je dis que chaque attribut ou fonction membre exposé depuis l'extérieur est susceptible d'être considéré comme une propriété du type envisagé.

    Je reste cependant conscient du fait qu'un type donné est largement plus que la somme des propriétés qu'il expose, entre autres (et sans doute pas uniquement), parce qu'il faut prendre la sémantique du type en compte.

    Cependant, il faut admettre qu'une part importante de ce qui défini un type est du... aux membres et aux fonctions membres qu'il expose à l'utilisateur.
    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. #146
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Lorsque tu écris un opérateur de conversion de const char* en std::string (ou en n'importe quel autre type de ton cru), tu réalise effectivement un transtypage, car tu obtiens au final un type différent du type d'origine.
    Ah, oui. J'avais oublié qu'on pouvait surcharger l'opérateur de cast en C++

    C'est, justement, parce que le mécanisme d'héritage nous garanti que ce sera le cas que tu dois veiller à ce que ce soit effectivement ce à quoi tu t'attend.

    LSP est "simplement" là pour te permettre de réaliser que c'est effectivement le cas et que c'est une absolue nécessité.

    Si tu en viens, dans un type dérivé, à restreindre l'accessibilité d'une fonction déclarée comme "accessible depuis l'extérieur" dans le type de base, tu va simplement à l'encontre de cette règle primordiale, et LSP te permet d'en prendre conscience parce que, une fois que tu as une instance du type dérivé, tu ne peux pas envisager d'appeler une fonction que tu es pourtant habilité à appeler depuis le type de base.
    Ah. Ja pense que j'ai capté ton raisonnement. En simplifiant, cela donne :

    - propriété = méthode ou attribut public d'une classe
    - type = ensemble de propriétés = ensemble de méthodes ou attributs publics d'une classe
    - LSP (appliqué au type) = principe qui veut que toutes les méthodes ou attributs publics d'une classe de base soit exposés dans une classe dérivée

    Donc le mécanisme d'héritage du C++ te garantit que le LSP est respecté.

    (En ce sens, le LSP est plus une "règle technique" pour écrire un mécanisme d'héritage dans un langage objet qu'un "règle conceptuelle" pour écrire l'implémentation)
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  7. #147
    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 pseudocode Voir le message
    Ah, oui. J'avais oublié qu'on pouvait surcharger l'opérateur de cast en C++
    Où ai-je parlé de surcharge de l'opérateur de cast en C++

    Je te fais juste remarquer que le transtypage est une pratique qui n'est absolument pas propre au paradigme objets.

    Si C++ fournit un certain nombre d'opérateur de transtypage destinés à apporter un minimum de sécurité, il ne faut pas oubier que le transtypage existe en C et dans d'autres langages qui n'ont strictement rien à voir avec le paradigme objets
    Ah. Ja pense que j'ai capté ton raisonnement. En simplifiant, cela donne :

    - propriété = méthode ou attribut public d'une classe
    - type = ensemble de propriétés = ensemble de méthodes ou attributs publics d'une classe
    Plus la sémantique que tu donnes au type en question
    - LSP (appliqué au type) = principe qui veut que toutes les méthodes ou attributs publics d'une classe de base soit exposés dans une classe dérivée
    C'est effectivement ce pour quoi je plaide.
    Donc le mécanisme d'héritage du C++ te garantit que le LSP est respecté.
    Non... tu applique une transitivité de mauvais aloi.

    L'héritage ne peut être envisagé que si LSP est respecté, et donc, si tu es dans une situation dans laquelle LSP n'est pas respecté, tu ne peux pas envisager l'héritage.

    Si, au moment où tu envisage l'héritage, tu te rends compte que LSP n'est pas respecté parce que tu estimes que toutes les propriétés valides pour type de base ne sont pas valides pour le type dérivé (comprend: certaines fonctions déclarées publiques dans le type de base sont déclarées dans une accessibilité restreinte dans le type dérivé), tu dois refuser l'héritage
    (En ce sens, le LSP est plus une "règle technique" pour écrire un mécanisme d'héritage dans un langage objet qu'un "règle conceptuelle" pour écrire l'implémentation)
    Non...

    LSP est un principe conceptuel qui présente les prérequis indispensables au fait d'envisager la relation la plus forte qui puisse exister entre deux types de données.

    Tu ne peux "aller plus loin" dans l'analyse dont le but est de déterminer si tu utilise ou non l'héritage que si tu es en accord avec LSP.

    Mais, avant de prendre la décision finale, il n'est pas impossible (tu sera d'ailleurs régulièrement confronté au problème) que tu doive également prendre d'autres règles et d'autres obligations propres aux circonstances en compte.

    Ces règles et obligations seront, par exemple, dues au langage ou au "style de programmation" que tu envisage d'utiliser / de mettre en oeuvre.

    Mais la prise en compte de ces règles et obligations ne vient que "bien après" avoir évalué le respect de LSP et "sous réserve" que LSP soit effectivement respecté.
    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

  8. #148
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Non... tu applique une transitivité de mauvais aloi.

    L'héritage ne peut être envisagé que si LSP est respecté, et donc, si tu es dans une situation dans laquelle LSP n'est pas respecté, tu ne peux pas envisager l'héritage.

    Si, au moment où tu envisage l'héritage, tu te rends compte que LSP n'est pas respecté parce que tu estimes que toutes les propriétés valides pour type de base ne sont pas valides pour le type dérivé (comprend: certaines fonctions déclarées publiques dans le type de base sont déclarées dans une accessibilité restreinte dans le type dérivé), tu dois refuser l'héritage
    Ah, ok. Tu envisage l'héritage seulement si le LSP est respecté. Je comprend mieux ton raisonnement.

    C'est juste l'inverse du mien, en fait, où les propriétés sont des comportements (contrats implémentés sous forme d'interfaces) et le LSP est une contrainte à respecter lors de la la spécialisation (= l'héritage).

    Les deux approches fonctionnent. Mais je suis tellement habitué à la modélisation objet des comportements (et pas des types) que ton approche ne me semble pas naturelle.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  9. #149
    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 pseudocode Voir le message
    Ah, ok. Tu envisage l'héritage seulement si le LSP est respecté. Je comprend mieux ton raisonnement.

    C'est juste l'inverse du mien, en fait, où les propriétés sont des comportements (contrats implémentés sous forme d'interfaces) et le LSP est une contrainte à respecter lors de la la spécialisation (= l'héritage).

    Les deux approches fonctionnent. Mais je suis tellement habitué à la modélisation objet des comportements (et pas des types) que ton approche ne me semble pas naturelle.
    Et pourtant, c'est une approche beaucoup plus saine.

    Si tu ne te base que sur la "commonalité" des comportements, tu arrives assez facilement, toute considération propre à la programmation par contrat mise à part, à accepter l'idée qu'une classe particulière en vienne à hériter d'une autre "simplement" parce que les deux classes présentent une interface et des comportement communs.

    Or, ce n'est pas forcément parce que deux classes exposent une interface commune que tu peux obligatoirement envisager la relation d'héritage:

    La notion d'héritage va en effet beaucoup plus loin que le simple fait de partager une interface et des comportements commun: il s'agit d'une relation est-un, au sens sémantique du terme (comprend: au sens du vocabulaire utilisé pour définir les attentes que tu as vis à vis de ces deux types).

    En effet, la notion même de l'héritage implique que, quel que soit le nombre de sous types qui héritent d'un type de base, de manière directe ou indirecte, dois décemment être en mesure de justifier le fait que tel sous type (direct ou indirect) EST-UN type de base.

    Je ne peux que rappeler que la conception doit être envisagée avec ordre et méthode: L'ordre et la méthode à utiliser sont les suivants:
    1. S'assurer que la sémantique (le "vocabulaire" utilisé pour définir les attentes que l'on a vis à vis des différents types) autorise l'héritage
    2. S'assurer que LSP est respecté
    3. S'assurer que le langage utilisé ne place pas de restrictions
    4. S'assurer que le "style de programmation" ne place pas de restrictions
    Le (1) veut attirer ton attention sur le fait que l'on ne peut décemment pas estimer que Vehicule EST-UN Abre, par exemple, même si l'on venait à admettre la possibilité de trouver une interface commune entre ces deux types: l'affirmation Vehicule EST-UN Arbre n'a strictement aucun sens au vu du vocabulaire que l'on utilise pour définir arbre et véhicule! Reporte toi, simplement, au définitions que peut donner le dictionnaire de ces deux termes

    On n'évalue, la deuxième condition (le respect de LSP) pour accepter l'héritage que si (1) nous a déjà donné le feu vert.

    Si on ne peut pas invoquer "n'importe quelle fonction publique" définie dans la classe de base au départ de la classe dérivée, toutes les propriétés valides pour la classe de base ne peuvent pas être considérées comme valides pour la classe dérivée, avec pour conséquence que l'héritage doit, là aussi, être refusé au profit d'une autre solution.

    Pour la suite, cela continue: il ne sert à rien de réfléchir aux éventuelles restrictions imposées par le langage si, dés le départ, on n'a pas obtenu l'accord de principe pour envisager l'héritage sur base des deux premières étapes.

    Nous ne pourrons envisager l'héritage en fonction des restrictions imposées par le langage que s'il y a effectivement du sens à dire que le type dérivé EST-UN type de base "amélioré" ET si LSP est effectivement respecté.

    Si la situation particulière dans laquelle on envisage l'héritage va à l'encontre de restrictions imposées par le langage, nous serons bien obligés de trouver une alternative (le langage saura sans doute nous y forcer ), même si les deux étapes précédentes nous avaient mené à estimer que nous pouvions envisager l'héritage.

    Enfin, les restrictions éventuellement imposées par un style de programmation remporteront la décision.

    Nous sommes toujours dans le cas où il ne sert strictement à rien de réfléchir à ces restrictions éventuelles si on a déjà été obligé de réfléchir à une alternative!

    Mais nous serons bel et bien obligé de réfléchir à une alternative si les restrictions imposées par un style de programmation nous interdisent d'avoir recours à l'héritage, même si nous avions déterminé qu'il étati sémantiquement cohérent, que LSP était respecté et que le langage visé l'autorisait.

    Si tu suis ces quatre étapes à la lettre, tu aura la quasi certitude (je laisse la place à un minimum de pondération ) que l'ensemble de ta conception sera effectivement stable et cohérent.

    Si, pour une raison ou une autre, tu viens à te dire que "bah, tant pis si la sémantique n'est pas présente" ou "bah, après tout, LSP n'est pas vraiment intéressant" ou encore "bah, quelle importance si le langage interdit l'héritage multiple" ou encore "après tout, qu'est-ce que vous voulez que je me fasse ch... a assurer la cohérence au niveau des postconditions" , il est clair que tu te prépares des problèmes sans noms, parce que les bases de ta conception ne sont pas assez stables

    Je rappelle cependant que la programmation par contrat est une des possibilités de programmation objets auxquelles tu peux réfléchir, mais que tu n'a absolument aucune obligation d'y recourir
    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

  10. #150
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Citation Envoyé par koala01 Voir le message
    De même, nous pourrions dire, en mathématique, que le fait d'être pair ou impair est une propriété de tout nombre entier, parce que c'est, encore une fois, intrinsèque au nombre entier que l'on étudie.
    On pourrais aussi dire que c'est une fonction qui va de l'ensemble de tout les éléments dans l'ensemble des booléen. Et que donc la propriété elle-même n'est pas intrinsèque à l'élément. Et que si pour un élément x P(x) est vraie, alors P est prouvable pour x. Donc par contre, la prouvabilité d'une propriété est lié à l'élément. Cette définition ne me semble pas plus fausse que la tienne.
    Citation Envoyé par koala01 Voir le message
    C'est pour cela que j'attirais l'attention sur le fait qu'une fonction libre ne peut a priori pas être considérée comme une propriété: Toute propriété fait indéniablement partie de ce que l'on pourrait appeler "l'essence même" de ce que l'on étudie.
    J'ai bien compris ton point de vue sur les fonction libre, raison pour laquel j'ai utilisé la terminalogie objet dans mon raisonnement (et donc une "méthode" pour le C++).
    Citation Envoyé par koala01 Voir le message
    En gros, il y a quatre questions qui méritent d'être posées quand on envisage le recours à l'héritage. Dans l'ordre:
    1. Est-il sémantiquement opportun de faire hériter X de Y (cf quelques lignes plus haut )
    2. LSP est-il respecté avec l'héritage
    Là je ne suis pas d'accord, je vois plûtot les principes de programmation (SRP, OCP, LSP, ISP, DIP), comme des axiomes servant à montrer qu'un architecture est valide : tu supposes une architecture, tu l'a soumet aux principes, si ils sont tous valide alors l'architecture est valide, sinon non. (<EDIT>Je laisse de coter les sémantiques, même si elles sont indispensable</EDIT>). Après, il est évident que lorsque l'on concoit, on vérifie progressivement.

    Pour tout ce que tu dis concernant le fait que le langage doit venir après, je suis parfaitement d'accord, donc oui raisonner avec le typeid n'est pas logique, et le LSP est violé par un changement de visibilité (cf le début du topic)

    Citation Envoyé par koala01 Voir le message
    En effet, la notion même de l'héritage implique que, quel que soit le nombre de sous types qui héritent d'un type de base, de manière directe ou indirecte, dois décemment être en mesure de justifier le fait que tel sous type (direct ou indirect) EST-UN type de base
    Ce qui me gène c'est que, à l'inverse du LSP, la relation IS-A n'est pas défini, et je vois d'ailleurs ce terme comme un autre facon de décrire le LSP (ie A IS-A B si et seulement si A sous-type de B et le LSP est respecté pour A et B) Et c'est, de mémoire, ce que dis Sutter à propos de la relation IS-A dans un des ces articles à propos de l'héritage (il dis quelque chose comme : "utiliser l'héritage si et seulement si la relation IS-A est respecté au sens du LSP").

  11. #151
    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 Flob90 Voir le message
    On pourrais aussi dire que c'est une fonction qui va de l'ensemble de tout les éléments dans l'ensemble des booléen. Et que donc la propriété elle-même n'est pas intrinsèque à l'élément. Et que si pour un élément x P(x) est vraie, alors P est prouvable pour x. Donc par contre, la prouvabilité d'une propriété est lié à l'élément. Cette définition ne me semble pas plus fausse que la tienne.
    Si ce n'est que "va de l'ensemble de tous les éléments dans l'ensemble des booléens" est une propriété de... la fonction et non du type ou de l'objet que tu manipule.

    Il n'est pas impossible que la propriété de la fonction soit évaluée au départ d'une des propriété du type ou de l'objet, mais tu ne peux pas en déduire pour autant que ta fonction libre est une propriété de l'objet ou du type: ta fonction manipule, utilise, si tu veux une propriété de l'objet
    Là je ne suis pas d'accord, je vois plûtot les principes de programmation (SRP, OCP, LSP, ISP, DIP), comme des axiomes servant à montrer qu'un architecture est valide : tu supposes une architecture, tu l'a soumet aux principes, si ils sont tous valide alors l'architecture est valide, sinon non. (les sémantiques doivent se déduire de ces principes en cherchant bien je pense). Après, il est évident que lorsque l'on concoit, on vérifie progressivement.
    Le fait est que, même si la validation se fait de manière quasi simultanée, avant d'en arriver à cette validation, il faut bien que tu te pose la question de savoir si tu crées une relation ou une autre, ou si tu ne la crées pas.

    Quand tu as un type X et que tu te trouves face à la nécessité de créer un type Y qui est "fort proche" du type X, tu te pose naturellement la question de savoir s'il est cohérent ... de faire hériter Y de X.

    Tu va donc utiliser les différentes règles (propres aux différents principes / lois / axiomes / règles particulières) afin de déterminer l'opportunité et la cohérence de la relation que tu envisage.

    Et chaque principe, loi, axiomes, règle particulièère agira comme un "GO / NO GO" pour la suite: s'il est respecté, tu peux "aller plus loin", s'il ne l'est pas, tu dois envisager une solution alternative.

    Ce n'est, en définitive, qu'une fois que la relation est tracée que tu peux, effectivement, valider ta conception sur base des principes, lois, axiomes, règles particulières qui entrent en jeu
    Pour tout ce que tu dis concernant le fait que le langage doit venir après, je suis parfaitement d'accord, donc oui raisonner avec le typeid n'est pas logique, et le LSP est violé par un changement de visibilité (cf le début du topic)
    C'est déjà pas mal... Même si je ne sais plus quelle était ta positon au début du débat
    Ce qui me gène c'est que, à l'inverse du LSP, la relation IS-A n'est pas défini, et je vois d'ailleurs ce terme comme un autre facon de décrire le LSP (ie A IS-A B si et seulement si A sous-type de B et le LSP est respecté pour A et B) Et c'est, de mémoire, ce que dis Sutter à propos de la relation IS-A dans un des ces articles à propos de l'héritage (il dis quelque chose comme : "utiliser l'héritage si et seulement si la relation IS-A est respecté au sens du LSP").
    C'est pour cela que j'essaye d'introduire la notion de sémantique (à défaut d'avoir un meilleur terme à proposer) comme prérequis à respecter.

    La première chose à laquelle il faudrait veiller, lorsque l'on envisage une relation EST-UN est, selon moi, que le vocabulaire du terme utilisé puisse être compatible avec cette relation.

    Je vais prendre un exemple que j'espère pouvoir rendre clair.

    Mettons trois classes ReturnType, Argument et Variable.

    ReturnType est destiné à représenter les données relatives au type de retour d'une fonction.

    A ce titre, il doit présenter une interface publique permettant:
    • de récupérer le nom du type (primitif ou défini par l'utilisateur) renvoyé
    • de récupérer le "cv-qualifier" appliqué à la valeur renvoyée
    • de récupérer le "spécificateur d'adresse" (le fait que le retour s'effectue par valeur, par référence ou par pointeur, pour rester dans le cadre du C++)
    Argument est destiné à représenter les données relatives aux arguments à transmettre à une fonction.

    A ce titre, il doit présenter exactement l'interface de ReturnType, plus la possibilité de récupérer le nom de l'argument.

    Pour terminer, Variable est destiné à représenter les données relatives aux variables que l'on peut manipuler dans un algorithme.

    A ce titre, il doit présenter exactement l'interface de Argument, plus la possibilité de récupérer (pour rester dans le domaine du C++) le "storage class specifier" (le fait qu'il s'agit d'une variable "extern", "static","register" ou "mutable", en C++).

    Si tu t'en tiens à l'approche "comportementale", tu pourrais estimer que Argument peut hériter de ReturnType et que Variable peut hériter de Argument.

    Sauf que, du point de vue du sens que je vais donner à ces différents types (du point de vue du pur vocabulaire), je ne peux décemment pas me résoudre à estimer qu'un argument... EST-UN type de retour, ni qu'une variable EST-UN argument.

    Je pourrais envisager de donner la possibilité d'obtenir une variable à partir d'un argument, voire, de donner la possibilité de comparer un argument ou une variable avec un type de retour afin de déterminer si la variable ou l'argument peuvent lorsque je devrai renvoyer une valeur, mais les trois types doivent rester totalement indépendants les uns des autres.

    Il n'y aurait d'ailleurs aucun sens à envisager de faire cohabiter des types de retour et des variables (ou des arguments) au sein d'une seule et même collection, or, c'est ce que permettent l'héritage et la notion de substituabilité de manière implicite.

    Et tu sais comme moi que, si on donne une possibilité, même aberrante, aux gens, on trouvera toujours bien un imbécile pour essayer d'en profiter (c'est la loi de Murphy )

    Par contre, si on ajoute une quatrième classe Members, destinée à représenter les informations relatives aux membres de classes ou de structures, qui présentent l'interface propre à Variable plus la possibilité de récupérer l'accessibilité qui est appliquée à ce membre, nous pourrions, effectivement, envisager de faire hériter cette classe supplémentaire de la classe Variable, car un membre n'est jamais... qu'une variable particulière en cela qu'elle fait partie intégrante d'un type défini par l'utilisateur.

    Dans l'ordre logique du raisonnement que tu va suivre, on pourrait donc dire que:
    1. tu constate certaines similitudes qui te font te poser la question de l'opportunité de l'héritage
    2. tu t'interroges sur la cohérence sémantique de l'héritage
    3. Si la cohérence sémantique est assurée, tu t'interroges sur le respect de LSP
    4. Si LSP est respecté, tu vérifies si le langage ne pose pas de restrictions à l'héritage
    5. S'il n'y a aucune restriction propre au langage à l'héritage, tu vérifie si le style de programmation ne pose pas ses propres restrictions
    Cette méthodologie peut tout aussi bien servir "d'aide à la décision" que de méthode de validation, d'ailleurs, les deux se feront, comme je l'ai dit, de manière souvent quasi simultanée.

    Mais rien n'empêche que cette méthodologie serve de méthode de validation bien longtemps après que les différentes relations entre les différents types n'aient été tracées sur ton diagramme de classe
    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

  12. #152
    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
    De nouveau, je suis loin d'avoir tout lu, je ne reagit guere qu'a ce que je cite:
    Citation Envoyé par koala01 Voir le message
    Dans l'ordre logique du raisonnement que tu va suivre, on pourrait donc dire que:
    1. tu constate certaines similitudes qui te font te poser la question de l'opportunité de l'héritage
    2. tu t'interroges sur la cohérence sémantique de l'héritage
    3. Si la cohérence sémantique est assurée, tu t'interroges sur le respect de LSP
    4. Si LSP est respecté, tu vérifies si le langage ne pose pas de restrictions à l'héritage
    5. S'il n'y a aucune restriction propre au langage à l'héritage, tu vérifie si le style de programmation ne pose pas ses propres restrictions
    Le LSP est pour moi un critere de cohérence sémantique et pas quelque chose de séparé et encore moins d'indépendant.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #153
    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
    Citation Envoyé par koala01 Voir le message
    Or, ce n'est pas forcément parce que deux classes exposent une interface commune que tu peux obligatoirement envisager la relation d'héritage:

    La notion d'héritage va en effet beaucoup plus loin que le simple fait de partager une interface et des comportements commun: il s'agit d'une relation est-un, au sens sémantique du terme (comprend: au sens du vocabulaire utilisé pour définir les attentes que tu as vis à vis de ces deux types).
    C'est une manière de voir les choses. Elle est complètement à l'opposé du duck-typing, dans laquelle le EST-UN s'apprécie par rapport au contexte d'utilisation et à l'interface (si je n'utilise que l'intersection de l'interface de mes deux objets, l'un est substituable à l'autre dans mon contexte).

    Et je ne crois pas que LSP et duck-typing s'opposent, au contraire.

  14. #154
    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 white_tentacle Voir le message
    Et je ne crois pas que LSP et duck-typing s'opposent, au contraire.
    Les deux sont a des niveaux differents (LSP c'est un principe de conception de programme, duck-typing decrit le comportement d'un langage) mais le typage structurel autorise des choses qui ne respectent pas le LSP.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  15. #155
    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
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Les deux sont a des niveaux differents (LSP c'est un principe de conception de programme, duck-typing decrit le comportement d'un langage) mais le typage structurel autorise des choses qui ne respectent pas le LSP.
    C'est bien dans ce sens là que je l'entends, quand je dis qu'ils ne s'opposent pas. Avec l'héritage classique, tu peux violer allègrement le LSP. Avec le duck-typing aussi. Et dans les deux cas, LSP (ainsi que d'autres principes de conception) va te permettre de différencier ce qui est "sûr" de ce qui est "casse-gueule".

    Par contre, duck-typing est pour moi un peu plus qu'un comportement de langage. C'est un mécanisme de conception au même titre que l'héritage (si je l'ai, je vais concevoir différemment de si je ne l'ai pas).

  16. #156
    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 white_tentacle Voir le message
    Par contre, duck-typing est pour moi un peu plus qu'un comportement de langage. C'est un mécanisme de conception au même titre que l'héritage (si je l'ai, je vais concevoir différemment de si je ne l'ai pas).
    La conception est toujours influencée par ce que permet le langage. Ou alors on se retrouve a mettre en place des mécanismes de contournement divers. Un préprocesseur spécialisé et de la génération de code dans des cas extrêmes.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  17. #157
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    L'intérêt du LSP, c'est que si B est-un A au sens LSP, tout le code que j'ai écrit pour A reste valide pour B. Je ne parle pas du code de A, ni de celui de B, mais bien du code de tous les clients de A (codes qui utilisent un A).

    Avec typeid et C++, je peux écrire du code pour lequel ce n'est pas le cas. (ce faisant, je casse la substituabilité de mes objets). Avec le changement de visiblité et C++, je ne peux pas (je ne casse pas la substituabilité de mes objets).

    Mais tu dis que le second mécanisme viole le LSP, et pas le premier ? Ça ne te semble pas plutôt l'inverse ?
    L'utilisation de typeid() dans un but contraire à OCP est une mauvaise chose (on en convient tous), mais ce n'est pas nécessairement une violation de LSP. Le fait de restreindre l'utilisation d'un objet selon une condition (que cette condition soit un test sur typeid() ou non ne change pas les propriétés de l'objet utilisé.

    Lorsqu'on parle de propriétés d'un type T, dans le cadre de la définition du LSP, on entends par la :

    1) les membres (méthodes et variables membres ou assimilée) accessibles de T (le constructeur n'est pas à proprement parler un membre de T ; aussi étrange que cela puisse paraître).
    2) les pré-conditions des méthodes de T
    3) les post-conditions des méthodes de T

    C'est tout (et c'est déjà beaucoup).

    L'existence ou non d'une fonction particulière dans T est une propriété ; le fait que cette fonction soit accessible en est une autre. J'ai déjà longuement parlé des pré-conditions et post-conditions dans un autre post il y a peu de temps (il est quelque part dans le coin ; peut être dans un autre fil), donc je ne vais pas en remettre une couche.

    Dire 'ce que je peux faire avec un objet de type T, je dois pouvoir le faire avec un objet de type S, sous-type de T' n'impose pas du tout les même restriction que la définition du LSP (même si certaines restrictions sont semblables), et induit en erreur sur son fonctionnement.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  18. #158
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    La conception est toujours influencée par ce que permet le langage. Ou alors on se retrouve a mettre en place des mécanismes de contournement divers. Un préprocesseur spécialisé et de la génération de code dans des cas extrêmes.
    Mythbuster confirme

    On ne peut concevoir sans s'affranchir du langage qui sera utilisé, car celui-ci nous impose des restrictions différentes d'un autre langage. L'existence ou non de fonctionnalités particulières (delegate ici, fonctions libres là, ...) va imposer ou proposer des choix qui peuvent avoir un impact important sur la conception d'un produit logiciel.

    Exemple avec la librairie standard du C++, et notamment les algorithmes de cette librairie, qui offre une conception radicalement différente des conteneurs de Java ou C#.

    Ca ne veut tout de même pas dire qu'on doit penser que le langage a raison face aux principes de conception OO. On se doit de les prendre en compte de manière prioritaires (ils sont par essence indépendants du langage objet utilisé).

    Damned, je travaille en C actuellement, et la plupart des documents que j'écrit pour mon client font de multiples références aux principes de conception OO.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  19. #159
    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
    Citation Envoyé par Emmanuel Deloget Voir le message
    L'utilisation de typeid() dans un but contraire à OCP est une mauvaise chose (on en convient tous), mais ce n'est pas nécessairement une violation de LSP. Le fait de restreindre l'utilisation d'un objet selon une condition (que cette condition soit un test sur typeid() ou non ne change pas les propriétés de l'objet utilisé.
    Pourtant, ça casse la substituabilité.

    Mon attente, en tant qu'utilisateur de code, est que, étant donné la signature suivante :

    et la hiérarchie suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    class A {}; 
    class B : public A {};
    le code suivant fonctionne :
    Si f s'amuse à faire un test (avec typeid) pour vérifier que param est bien de type A (ça a l'air stupide sur un exemple aussi simple, mais je l'ai vu faire sur des hiérarchies "fermées", avec un beau test sur chacun des types possibles), ça ne fonctionne plus.

    Personnellement, je pars du principe que tout mécanisme qui empêche (permet de casser) la substituabilité contrevient au principe de substitution (de Liskov). Ca ressemble tellement à une tautologie que j'ai du mal à imaginer comment défendre l'inverse. Ca ne veut pas dire que le mécanisme est bon à jeter, juste qu'il faut faire particulièrement attention quand on l'utilise.

    Inversement, j'ai un peu de mal avec l'idée que quelque chose qui n'empêche pas la substituabilité contrevienne au principe de substitution (toujours de Liskov)... Qui est pourtant ce que nombreux défendent ici.

  20. #160
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Dire 'ce que je peux faire avec un objet de type T, je dois pouvoir le faire avec un objet de type S, sous-type de T' n'impose pas du tout les même restriction que la définition du LSP (même si certaines restrictions sont semblables), et induit en erreur sur son fonctionnement.
    "What is wanted here is something like the following substitution property: If
    for each object o1 of type S there is an object o2 of type T such that for all
    programs P defined in terms of T, the behavior of P is unchanged when o1 is
    substituted for o2 then S is a subtype of T."

    (Barbara Liskov, “Data Abstraction and Hierarchy", 1988)


    Restons pragmatique et ne donnons pas au LSP des super-pouvoirs qu'il ne devrait pas avoir.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

Discussions similaires

  1. Réponses: 2
    Dernier message: 02/10/2008, 16h37
  2. Fonction appelant une fonction virtuelle pure
    Par oodini dans le forum C++
    Réponses: 12
    Dernier message: 19/09/2008, 08h24
  3. Une fonction virtuelle ne peut pas retourner un template!
    Par coyotte507 dans le forum Langage
    Réponses: 10
    Dernier message: 08/02/2008, 20h39
  4. Problème de visibilité d'une fonction
    Par hello2lu dans le forum VBA Access
    Réponses: 8
    Dernier message: 03/07/2007, 15h20
  5. Réponses: 2
    Dernier message: 05/03/2006, 19h29

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