Si je déclare une classe de base (ou une classe d'interface) et spécifie une valeur par défaut pour un ou plusieurs de ses paramètres, les classes dérivées doivent-elles spécifier les mêmes valeurs par défaut et si ce n'est pas le cas, quelles valeurs par défaut se manifesteront dans les classes dérivées?
Addendum: Je suis également intéressé par la manière dont cela peut être géré entre différents compilateurs et par toute entrée sur la pratique «recommandée» dans ce scénario.
Réponses:
Les virtuels peuvent avoir des valeurs par défaut. Les valeurs par défaut de la classe de base ne sont pas héritées par les classes dérivées.
La valeur par défaut utilisée - c'est-à-dire la classe de base «ou une classe dérivée» - est déterminée par le type statique utilisé pour effectuer l'appel à la fonction. Si vous appelez via un objet de classe de base, un pointeur ou une référence, la valeur par défaut indiquée dans la classe de base est utilisée. Inversement, si vous appelez via un objet de classe dérivée, un pointeur ou une référence, les valeurs par défaut indiquées dans la classe dérivée sont utilisées. Il y a un exemple sous la citation standard qui le démontre.
Certains compilateurs peuvent faire quelque chose de différent, mais c'est ce que disent les normes C ++ 03 et C ++ 11:
Voici un exemple de programme pour montrer quelles valeurs par défaut sont sélectionnées. J'utilise
struct
s ici plutôt queclass
es simplement par souci de concision -class
etstruct
sont exactement les mêmes dans presque tous les sens, sauf la visibilité par défaut.La sortie de ce programme (sur MSVC10 et GCC 4.4) est:
la source
C'était le sujet de l'un des premiers messages de Herb Sutter sur le gourou de la semaine .
La première chose qu'il dit sur le sujet est NE FAITES PAS CELA.
Plus en détail, oui, vous pouvez spécifier différents paramètres par défaut. Ils ne fonctionneront pas de la même manière que les fonctions virtuelles. Une fonction virtuelle est appelée sur le type dynamique de l'objet, tandis que les valeurs de paramètre par défaut sont basées sur le type statique.
Donné
vous devriez obtenir A :: foo1 B :: foo2 B :: foo1
la source
C'est une mauvaise idée, car les arguments par défaut que vous obtenez dépendront du type statique de l'objet, tandis que la
virtual
fonction distribuée dépendra du type dynamique .Autrement dit, lorsque vous appelez une fonction avec des arguments par défaut, les arguments par défaut sont substitués au moment de la compilation, que la fonction le soit
virtual
ou non.@cppcoder a donné l'exemple suivant dans son [clos] question :
Ce qui produit la sortie suivante:
À l'aide de l'explication ci-dessus, il est facile de comprendre pourquoi. Au moment de la compilation, le compilateur remplace les arguments par défaut des fonctions membres des types statiques des pointeurs, ce qui rend la
main
fonction équivalente à ce qui suit:la source
Comme vous pouvez le voir dans les autres réponses, c'est un sujet compliqué. Au lieu d'essayer de le faire ou de comprendre ce qu'il fait (si vous devez demander maintenant, le responsable devra le demander ou le rechercher dans un an).
Au lieu de cela, créez une fonction publique non virtuelle dans la classe de base avec les paramètres par défaut. Ensuite, il appelle une fonction virtuelle privée ou protégée qui n'a pas de paramètres par défaut et est remplacée dans les classes enfants si nécessaire. Ensuite, vous n'avez pas à vous soucier des détails de la façon dont cela fonctionnerait et le code est très évident.
la source
C'est une partie que vous pouvez probablement comprendre raisonnablement bien en testant (c'est-à-dire que c'est une partie suffisamment courante du langage pour que la plupart des compilateurs y parviennent presque certainement et à moins que vous ne voyiez des différences entre les compilateurs, leur sortie peut être considérée comme faisant assez bien autorité).
la source
Comme d'autres réponses l'ont détaillé, c'est une mauvaise idée. Cependant, puisque personne ne mentionne une solution simple et efficace, la voici: Convertissez vos paramètres en struct et vous pourrez alors avoir des valeurs par défaut pour les membres de struct!
Donc au lieu de,
fais ça,
la source