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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    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
    Par défaut Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?
    [Edit 3DArchi]
    Suite à cette question : Accès à une méthode virtuelle protégée ou privée, un débat s'est ouvert pour savoir si le changement de visibilité d'une fonction virtuelle dans une classe dérivée est un viol du LSP.
    Un des énoncés du LSP (ou Principe de Substituion de Liskov introduit par Barbara Liskov en 1987) peut être le suivant (cf ici ou ici):
    Si pour chaque objet o1 de type S, il y a un objet o2 de type T tel que pour tous les programmes P définis avec le type T, le comportement de P reste inchangé lorsque o1 est substitué à o2 alors S est un sous-type de T.
    La question initiale portait sur le changement de visibilité d'une fonction virtuelle dans la classe dérivée par rapport à la classe de base. Les intervenants s'accordent de reconnaitre que cette pratique est peu justifiable d'un point de vue conception, donc le débat ne porte pas la dessus.

    La question posée dans cette discussion est :
    Le changement de visibilité d'une fonction virtuelle est-il un viol du LSP ?

    [/Edit]



    Citation Envoyé par koala01 Voir le message
    Le fait de redéfinir une fonction virtuelle en changeant sa visibilité est, surtout, une transgression grave du principe de subsitution de Liskov
    En fait, non, j'ai beau retourner dans tous les sens, mais je ne vois pas en quoi ça viole le LSP, si on s'en tient à une approche objet.

    Après, si on rajoute les génériques, ça devient différent. Mais comme ça sera résolu à la compilation, le LSP a moins de sens. C'est un peu bizarre d'avoir B polymorphique à A, tout en étant d'un concept (au sens c++1x) différent, mais j'ai du mal à trouver une bonne raison de l'empêcher (à peu près autant de mal qu'à y trouver un intérêt).

  2. #2
    Membre Expert

    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 : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Si tu réduis la visibilité il est clair que u violes le LSP, le LSP dit que toute propriété valide sur une mère l'est sur une fille, si tu réduis l'interface, tu rends invalide ceci (la propriété : "peut envoyer le message xxx" n'est pas valide).
    Par contre si tu l'augmentes, ca ne l'invalide pas. Mais ca reste assez illogique de le faire, une méthode privé virtuel permet de ne définir qu'un comportement. Si tu passes de privé (ou protégé) à publique, tu choisies délibérement de faire de cette fonction un élément de l'interface alors que le concepteur de la classe mère avait déterminé qu'elle ne devait pas en faire partie (peut-etre pour respecter le SRP ?).
    J'ai du mal à voir ce qui pourrait motiver le choix de faire d'un élément qui ne fait que définir un comportement, un élément de l'interface.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Comme j'arrive un peu tard, je ne peux qu'appuyer les écrits de Flob90...

    La base du raisonnement de Liskov, c'est que toute propriété (comprend: la capacité de recevoir, d'émettre ou de répondre (à) un message donné) valide pour la classe de base doit être valide pour toute classe dérivée, de manière directe ou indirecte.

    Cela sous entend que si la classe A a une propriété XXX qui est valide pour A, la propriété devra aussi être valide pour toute classe qui dérive de A, mais aussi pour toute classe qui dérive d'une classe qui dérive d'une (on pourrait continuer 106 ans comme cela) classe qui dérive de A.

    Si tu réduis la visibilité d'une fonction prévue dans l'interface publique de la classe mère, tu essaye d'invalider la propriété en question: Tu ne peux en effet pas envisager sereinement de placer une instance de la classe dérivée dans une collection manipulant (des pointeurs sur) la classe de base, car tu cours le risque que l'utilisateur fasse appel, en toute bonne fois, à la propriété en question.

    A l'inverse, si une fonction est protégée ou privée dans la classe de base, elle n'est là que pour faciliter le travail des autres fonctions membres de la classe, voire le travail des fonctions membres des classes dérivées.

    Elle n'est donc qu'à "usage interne" en quelque sorte, et fait littéralement partie de ce que l'on pourrait appeler les "détails d'implémentation".

    Il n'y a donc aucune raison pour exposer cette fonction au tout publique dans les 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

  4. #4
    Membre Expert
    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
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Si tu réduis la visibilité d'une fonction prévue dans l'interface publique de la classe mère, tu essaye d'invalider la propriété en question: Tu ne peux en effet pas envisager sereinement de placer une instance de la classe dérivée dans une collection manipulant (des pointeurs sur) la classe de base, car tu cours le risque que l'utilisateur fasse appel, en toute bonne fois, à la propriété en question.
    Sauf que la fonction est toujours appelable via l'interface de A, et que donc le LSP n'est pas malmené de ce point de vue. Tu peux tout à fait le mettre dans une collection, car l'appel à la propriété en question fonctionnera parfaitement (même s'il ne fonctionnerait plus aprés downcast).

    Non, le seul cas qui pose problème par rapport au LSP, c'est l'utilisation de B comme paramètre d'une classe template. Mais fondamentalement, je ne crois pas que le LSP ait été prévu pour ça, ça sera détecté à la cmnpilation donc ça ne me semble pas un souci autre mesure.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Sauf que la fonction est toujours appelable via l'interface de A, et que donc le LSP n'est pas malmené de ce point de vue. Tu peux tout à fait le mettre dans une collection, car l'appel à la propriété en question fonctionnera parfaitement (même s'il ne fonctionnerait plus aprés downcast).
    C'est justement parce que la fonction est accessible publiquement depuis l'interface de A que LSP est malmené...

    Vu que la fonction ne devrait pas être accessible publiquement pour la classe dérivée.

    Comprend moi: Si tu n'a une vision que de la classe dérivée, en tant qu'utilisateur, tu ne vas jamais tenter d'appeler une fonction protégée ou privée depuis l'extérieur, vu que tu t'attend à avoir un message proche de "foo is private / protected in this context".

    A l'inverse, si tu n'a qu'une vision de la classe de base, toujours en tant qu'utilisateur de celle-ci, tu envisagera sans problème d'appeler la fonction, vu qu'elle est... publique, et fait donc partie de l'interface dont tu dispose pour interagir avec ton objet.

    Quel que soit le sens du point de vue où tu te place, tu as donc une incohérence du seul fait que tu peux faire quelque chose d'un coté que tu ne peux pas faire de l'autre.

    LSP n'est donc, purement et simplement, pas respecté.

    En gros, l'héritage (public) peut ajouter des possibilités à l'interface de base, mais pas en supprimer
    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
    Membre Expert
    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
    Par défaut
    Citation Envoyé par koala01 Voir le message
    C'est justement parce que la fonction est accessible publiquement depuis l'interface de A que LSP est malmené...
    Pas vraiment, non. B reste substituable à A, tant que l'on considère que c'est un A. Ca donne une situation un peu étrange, où une instance de B est toujours substituable à une instance de A, mais où le type B n'est plus substituable au type A (d'où le fait que ça ne marche pas pour les génériques).

    Comprend moi: Si tu n'a une vision que de la classe dérivée, en tant qu'utilisateur, tu ne vas jamais tenter d'appeler une fonction protégée ou privée depuis l'extérieur, vu que tu t'attend à avoir un message proche de "foo is private / protected in this context".
    Tout à fait d'accord.

    A l'inverse, si tu n'a qu'une vision de la classe de base, toujours en tant qu'utilisateur de celle-ci, tu envisagera sans problème d'appeler la fonction, vu qu'elle est... publique, et fait donc partie de l'interface dont tu dispose pour interagir avec ton objet.
    Là aussi je suis d'accord.

    Quel que soit le sens du point de vue où tu te place, tu as donc une incohérence du seul fait que tu peux faire quelque chose d'un coté que tu ne peux pas faire de l'autre.
    Si, je peux des deux côtés. Ce que tu occultes, c'est que l'interface d'une classe ne se restreint pas à ce qu'elle définit, mais aussi à tout ce dont elle hérite. Et donc, si j'ai la chose suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class A {
    public:
      virtual void f();
    };
    class B: public A {
    protected:
      virtual void f();
    }
    L'interface de B contient toujours ce public A::f() (la preuve : on peut l'appeler ).

    LSP n'est donc, purement et simplement, pas respecté.
    LSP est parfaitement respecté sur les instances des objets. Le problème se pose pour les types eux-mêmes, mais le LSP ne s'intéresse qu'aux instances.

    En gros, l'héritage (public) peut ajouter des possibilités à l'interface de base, mais pas en supprimer
    Il ne la supprime pas vraiment, puisqu'elle reste disponible si tu utilises l'interface de base. Partout où tu utilises une instace de A, tu peux utiliser une instance de B à la place. C'est en ce sens là que pour moi, le LSP n'est pas malmené.

    Par contre, je n'ai toujours pas compris à quoi ça peut servir

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