3.7.8. Les fonctions membres d'une classe ne seront pas déclarées virtuelles par défaut. Elles le seront uniquement si cette fonction correspond à un point de variation prévu lors de la conception de classe.
Une école tend à définir toutes les fonctions en virtuel : «
mettons la fonction en virtuel, quelqu'un pourrait vouloir la supplanter ». Seulement...
Si une fonction ne correspond pas à un point de variation [Coplien1998] prévu lors de la conception, il reste peu probable que l'on puisse étendre le système simplement parce que la fonction était virtuelle. Bien souvent, rajouter correctement un point de variation non initialement prévu demande un refactoring non trivial du code, c'est-à-dire bien plus qu'ajouter un simple "virtual".
Bien sûr, plus les fonctions d'une classe respectent la règle Section 3.1.3, «
Une fonction doit faire une chose, et doit le faire bien. Ainsi, le nombre de lignes d'instructions efficaces (générant du code exécutable) d'une fonction doit être limité à 50 lignes, soit environ un demi écran moderne. On évitera également l'abondance de niveaux d'imbrications. », plus il est simple d'introduire des points de variations à la volée. Seulement si toutes sont virtuelles, cela veut aussi dire que toutes ces fonctions membre (en nombre plus ou moins important) peuvent être supplantées. Les classes filles auraient alors une visibilité complète de la classe mère. De cette rupture d'encapsulation inter-générations, il devient alors vite complexe de savoir ce qui peut être supplanté, et sous quelles conditions (contraintes).
De plus, les hiérarchies polymorphes ayant naturellement une sémantique d'entité, définir virtuelle une quelconque fonction membre d'une classe à sémantique de valeur n'a aucun sens. C'est aussi pour cela qu'aucun conteneur de la bibliothèque standard ne dispose de fonction membre virtuelle (voir la règle Section 3.7.7, «
Éviter de dériver de classes non prévues pour être des classes de base. »).
Enfin, virtual introduit un sur-coût lors d'un appel de fonction où il n'était pas nécessaire. De fait, pour des raisons d'optimisation, on évite également de payer inutilement pour un service dont on n'a pas besoin : à savoir un branchement conditionnel déterminé à l'exécution (NB: il n'y aucune différence de rapidité, voire de meilleures performances sont à attendre de virtual par rapport à des if en chaîne, un switch-case, des tables d'indirection, etc.).
Références
[
Meyers2002], [
Hejlsberg2003].
Partager