Quel est le but du final
mot clé en C ++ 11 pour les fonctions? Je comprends que cela empêche le remplacement de fonction par des classes dérivées, mais si tel est le cas, n'est-il pas suffisant de déclarer vos final
fonctions comme non virtuelles ? Y a-t-il autre chose qui me manque ici?
143
virtual
mot - clé ou non.func
n'est pas virtuel, il n'y a donc rien à remplacer et donc rien à marquer commeoverride
oufinal
.Réponses:
Ce qui vous manque, comme idljarn déjà mentionné dans un commentaire, c'est que si vous surchargez une fonction d'une classe de base, vous ne pouvez pas la marquer comme non virtuelle:
la source
virtual
peut provoquer des erreurs, et C ++ 11 a ajouté laoverride
balise à une fonction qui détectera cette situation et ne parviendra pas à se compiler lorsqu'une fonction censée remplacer se cacheIl s'agit d'empêcher une classe d'être héritée. De Wikipedia :
Il est également utilisé pour marquer une fonction virtuelle afin d'éviter qu'elle ne soit surchargée dans les classes dérivées:
Wikipédia fait en outre un point intéressant :
Cela signifie que ce qui suit est autorisé:
la source
"final" permet également à une optimisation du compilateur de contourner l'appel indirect:
avec "final", le compilateur peut appeler
CDerived::DoSomething()
directement de l'intérieurBlah()
, voire en ligne. Sans cela, il doit générer un appel indirect à l'intérieur deBlah()
carBlah()
pourrait être appelé à l'intérieur d'une classe dérivée qui a été surchargéeDoSomething()
.la source
Rien à ajouter aux aspects sémantiques de "final".
Mais j'aimerais ajouter au commentaire de Chris Green que "final" pourrait devenir une technique d'optimisation de compilateur très importante dans un avenir pas si lointain. Non seulement dans le cas simple qu'il a mentionné, mais aussi pour des hiérarchies de classes du monde réel plus complexes qui peuvent être "fermées" par "finales", permettant ainsi aux compilateurs de générer un code de répartition plus efficace qu'avec l'approche vtable habituelle.
L'un des principaux inconvénients des vtables est que pour tout objet virtuel de ce type (en supposant 64 bits sur un processeur Intel typique), le pointeur à lui seul consomme 25% (8 sur 64 octets) d'une ligne de cache. Dans le genre d'applications que j'aime écrire, cela fait très mal. (Et d'après mon expérience, c'est l'argument n ° 1 contre C ++ d'un point de vue puriste des performances, c'est-à-dire par les programmeurs C.)
Dans les applications qui nécessitent des performances extrêmes, ce qui n'est pas si inhabituel pour C ++, cela pourrait en effet devenir génial, ne nécessitant pas de contourner ce problème manuellement en style C ou en jonglant avec des modèles bizarres.
Cette technique est connue sous le nom de dévirtualisation . Un terme à retenir. :-)
Il y a un excellent discours récent d'Andrei Alexandrescu qui explique assez bien comment vous pouvez contourner de telles situations aujourd'hui et comment «final» pourrait faire partie de la résolution de cas similaires «automatiquement» à l'avenir (discuté avec les auditeurs):
http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly
la source
Final ne peut pas être appliqué aux fonctions non virtuelles.
Il ne serait pas très significatif de pouvoir marquer une méthode non virtuelle comme «finale». Donné
a->foo()
appellera toujoursA::foo
.Mais, si A :: foo l'était
virtual
, alors B :: foo le remplacerait. Cela pourrait être indésirable, et il serait donc logique de rendre la fonction virtuelle définitive.La question est cependant de savoir pourquoi autoriser les fonctions finales sur les fonctions virtuelles. Si vous avez une hiérarchie profonde:
Ensuite, le
final
«plancher» sur combien de dépassement peut être fait. D'autres classes peuvent étendre A et B et les remplacerfoo
, mais si une classe étend C, ce n'est pas autorisé.Donc, cela n'a probablement pas de sens de faire le toto «de premier niveau»
final
, mais cela pourrait avoir un sens plus bas.(Je pense cependant qu'il est possible d'étendre les mots final et de priorité aux membres non virtuels. Ils auraient cependant une signification différente.)
la source
final
. Par exemple, si vous savez que vous voulez que tous lesShape
sfoo()
soient, quelque chose de prédéfini et défini qu'aucune forme dérivée ne doit modifier. Ou ai-je tort et il existe un meilleur modèle à utiliser pour ce cas? EDIT: Oh, peut-être parce que dans ce cas, il ne faut tout simplement pas faire le plus haut niveaufoo()
virtual
pour commencer? Mais quand même, il peut être caché, même s'il est appelé correctement (polymorphiquement) viaShape*
...Voici un cas d'utilisation du mot-clé `` final '' que j'affectionne:
la source
final
ajoute une intention explicite de ne pas avoir votre fonction remplacée, et provoquera une erreur du compilateur si cela est violé:Dans l'état actuel du code, il compile et
B::foo
remplaceA::foo
.B::foo
est également virtuel, d'ailleurs. Cependant, si nous changeons # 1 envirtual int foo() final
, alors c'est une erreur du compilateur, et nous ne sommes pas autorisés à remplacerA::foo
davantage dans les classes dérivées.Notez que cela ne nous permet pas de «rouvrir» une nouvelle hiérarchie, c'est-à-dire qu'il n'y a aucun moyen de créer
B::foo
une nouvelle fonction indépendante qui peut être indépendamment à la tête d'une nouvelle hiérarchie virtuelle. Une fois qu'une fonction est définitive, elle ne peut plus jamais être déclarée dans une classe dérivée.la source
Le mot-clé final vous permet de déclarer une méthode virtuelle, de la remplacer N fois, puis d'exiger que «cela ne puisse plus être remplacé». Cela serait utile pour restreindre l'utilisation de votre classe dérivée, afin que vous puissiez dire "Je sais que ma super classe vous permet de remplacer cela, mais si vous voulez dériver de moi, vous ne pouvez pas!".
Comme d'autres affiches l'ont souligné, il ne peut pas être appliqué à des fonctions non virtuelles.
L'un des objectifs du mot-clé final est d'empêcher le remplacement accidentel d'une méthode. Dans mon exemple, DoStuff () peut avoir été une fonction d'assistance que la classe dérivée doit simplement renommer pour obtenir un comportement correct. Sans finale, l'erreur ne serait pas découverte avant les tests.
la source
Le mot clé final en C ++ lorsqu'il est ajouté à une fonction, l'empêche d'être remplacé par une classe de base. De plus, lorsqu'il est ajouté à une classe, il empêche l'héritage de tout type. Prenons l'exemple suivant qui montre l'utilisation du spécificateur final. Ce programme échoue lors de la compilation.
Aussi:
la source
Supplément à la réponse de Mario Knezović:
Le code ci-dessus montre la théorie, mais pas réellement testé sur de vrais compilateurs. Très apprécié si quelqu'un colle une sortie démontée.
la source