Developpez.com - Rubrique C++

Le Club des Développeurs et IT Pro

Discussion : Peut-on créer une méthode virtuelle const ?

Le 2008-11-02 00:52:32, par NiamorH, Membre éprouvé
Voila, il est plus de minuit et demi maintenant et je me pose une question existencielle :

Les méthodes d'interface et autres méthodes virtuelles "ont-elles le droit" d'être déclarées const?

A moins de cas particuliers, mais je n'en vois pas, même en cherchant, c'est à l'implémentation de décider si, oui ou non, la méthode redéfinie va être amenée à modifier l'objet.

Quel est votre avis la-dessus ?
  Discussion forum
27 commentaires
  • JolyLoic
    Rédacteur/Modérateur
    Oui, elles en ont le droit. Être const fait partie du contrat, et c'est la classe de base qui fixe le contrat. C'est elle qui dit qu'une fonction aura N paramètres de tels ou tels types, c'est aussi elle qui dit si on pourra l'appeler sur un objet constant.
  • Alp
    Expert éminent sénior
    Exemple "bête" :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class GraphicObject
    {
      public :
        virtual void Draw() const = 0;
    };
    
    class Ball : public GraphicObject
    {
      public : 
        void Draw() const { /* on affiche la balle */ }
    }
    La méthode Draw ne modifiant pas l'instance, on peut la "const-qualifier", et ainsi elle pourra être appelée sur des objets constants, tout en préservant le polymorphisme désiré.
  • NiamorH
    Membre éprouvé
    Bonjour,

    si j'écris ton exemple tel quel, Alp, j'ai l'erreur "cannot instanciate abstract class" car la méthode Draw de Ball n'est justement pas const alors que celle GraphicObject est déclarée comme l'étant.

    Et c'est bien là le fond du problème. Je suis tout à fait d'accord avec vous pour dire que décider de rendre une méthode virtuelle const établi un contrat qui doit suivre une logique et que cela doit être fait lors du design de la classe abstraite de base.
    Seulement je trouve pleins de cas où cela pose problème.

    Si je reprends l'exemple de l'objet graphique et sa méthode Draw() : l'objet est dans un certain état (position, couleur etc.) et on lui demande de s'afficher en l'état, à priori sans le modifier, de façon à ce que si l'on appelle à nouveau cette méthode juste derrière, le même affichage devrait nous être donné. Donc notre méthode est const vis à vis de l'objet graphique.

    Alp, tu as surement raisonné ainsi et j'aurais certainement fait pareil. Mais toujours en continuant l'exemple, imaginons que j'implémente ObjetGraphique et mon implémentation nécessite beaucoups de précalculs non négligeables avant de pouvoir effectivement se dessiner. Ces calculs dépendent de l'état de l'objet et ne devraient pas avoir à être ré-éxécutés si l'état n'a pas changé depuis le dernier appel à Draw(). Et bien, à part en déclarant des variables mutable, je ne peux pas sauver mes précalculs dans Draw().

    Voilà ce qui me chiffone depuis hier.
  • Alp
    Expert éminent sénior
    En fait j'ai simplement oublié le const...

    Car j'étais fatigué

    Mais tu peux pas casser la qualification const, effectivement. J'édite le code ci-dessus
  • JolyLoic
    Rédacteur/Modérateur
    Envoyé par NiamorH
    imaginons que j'implémente ObjetGraphique et mon implémentation nécessite beaucoups de précalculs non négligeables avant de pouvoir effectivement se dessiner. Ces calculs dépendent de l'état de l'objet et ne devraient pas avoir à être ré-éxécutés si l'état n'a pas changé depuis le dernier appel à Draw(). Et bien, à part en déclarant des variables mutable, je ne peux pas sauver mes précalculs dans Draw().
    Et justement, tu peux les déclarer mutable, et alors, ça marche. Je ne vois pas trop ce qui te gène dans ce cas.

    Et le mutable n'est pas là "pour faire plaisir" à la classe de base : Il est là parce que, indépendamment de toute autre chose, ton objet n'est pas sémantiquement modifié par son affichage, le fait qu'il y ait des pré-calculs mis en cache n'étant qu'un détail d'implémentation ne devant pas apparaître dans l'interface.
  • Médinoc
    Expert éminent sénior
    Pour moi, un truc qui "aide" à comprendre les variables mutables, c'est de se dire que ce ne sont pas des variables à part entière de la classe, juste des détails d'implémentation.
    Ce qui est le cas pour la plupart des utilisations de variables mutables: Comptage de références intrusif, cache, et compteurs d'appels...
  • koala01
    Expert éminent sénior
    Salut,

    Le role d'une méthode const est de préciser au compilateur "cette méthode ne modifie pas l'objet".

    Par le fait de modifier l'objet, il faut comprendre le fait de modifier les "propriétés intrinsèques" qui font que ta balle rouge et bleue d'un diametre de N n'est pas une balle verte et jaune d'un diamètre de 2N, et que, au moment de l'appel, sa position et son "orientation" (le fait que le rouge soit en haut à gauche et le bleu en bas à droite) se seront pas modifiée.

    Par contre, si pour t'éviter d'avoir à recalculer en permanence l'aspect à donner à ta balle, tu décide de mettre cet aspect dans un cache, tu te trouve exactement dans le cas d'utilisation d'une variable mutable: ca ne modifie absolument pas les propriétés intrinsèques de la balle, cela ne modifie que la manière dont la méthode d'affichage va représenter la balle dans la situation donnée.
  • NiamorH
    Membre éprouvé
    Effectivement, le mot clef mutable est la solution que j'utilise. Mais ça m'a toujours géné d'y avoir recours. Dans ma tête je me suis toujours dis "tu as dû mal penser quelque chose pour en arriver à devoir t'en servir."

    Peut être que je me fais du mauvais sang pour rien après tout.
  • Médinoc
    Expert éminent sénior
    Je me disais la même chose au début, c'est d'ailleurs pourquoi j'ai restreint mon utilisation de mutable au comptage de références intrusif et aux caches...
  • koala01
    Expert éminent sénior
    Effectivement, tu te fais beaucoup de mauvais sang pour rien...

    Bien sur, comme beaucoup de choses en programmation, il faut toujours se poser la question de savoir si oui ou non il est opportun de déclarer un membre mutable...

    Bien sur, l'abus de déclaration de membres mutables est au minimum le signe d'une réflexion sans doute erronée.

    Mais, une fois que tu a clairement défini qu'un membre agit comme un cache, comme une machine à état qui peut devenir invalide à n'importe quel moment (y compris au sein de méthodes constantes), et que la modification de ce membre ne modifie en rien les "propriétés intrinsèques" de l'objet en cours, tu es clairement dans le cadre dans lequel il est "opportun" de déclarer le membre mutable