C++ 11 a ajouté override
pour garantir que les fonctions membres que vous écrivez que vous avez l'intention de remplacer les fonctions virtuelles de classe de base le font (ou ne compileront pas).
Mais dans une grande hiérarchie d'objets, vous pouvez parfois accidentellement finir par écrire une fonction membre qui remplace un virtuel de classe de base lorsque vous ne le vouliez pas! Par exemple:
struct A {
virtual void foo() { } // because obviously every class has foo().
};
struct B : A { ... };
class C : B {
private:
void foo() {
// was intended to be a private function local to C
// not intended to override A::foo(), but now does
}
};
Existe-t-il un indicateur/extension du compilateur qui émettrait au moins un avertissement sur C::foo
? Pour plus de lisibilité et d'exactitude, je voudrais juste faire en sorte que tous les remplacements utilisent override
.
On dirait que la version GCC 5.1 a ajouté exactement le avertissement que je cherchais:
-Wsuggest-override
Avertir de remplacer les fonctions virtuelles qui ne sont pas marquées avec le mot-clé override.
Compilation avec -Wsuggest-override
-Werror=suggest-override
imposerait alors que tous les remplacements utilisent override
.
Il y a deux choses que tu peux faire.
Tout d'abord, Clang 3.5 et supérieur ont un avertissement -Winconsistent-missing-override
(Déclenché par -Wall
). Cela ne fonctionne pas tout à fait pour votre exemple, mais seulement si vous voulez ajouter une void foo() override {}
à class B
Et non dans class C
. Ce que vous voulez réellement, c'est -Wmissing-override
, Pour localiser tous les override
manquants, pas seulement ceux qui manquent de manière incohérente. Ce n'est actuellement pas fourni, mais vous pourriez vous plaindre sur la liste de diffusion Clang et ils pourraient l'ajouter.
Deuxièmement, vous utilisez l'astuce de Howard Hinnant to temporairement add final
à la fonction membre de classe de base et recompiler. Le compilateur recherchera ensuite toutes les autres classes dérivées qui tentent de remplacer la fonction membre de base virtual
. Vous pouvez ensuite corriger ceux qui manquent. C'est un peu plus de travail et nécessite de revérifier fréquemment lorsque votre hiérarchie de classes se développe.
Le problème que je vois avec -Werror=suggest-override
est qu'il ne vous permet pas d'écrire ce qui suit:
void f() final {...}
Même s'il existe un override
implicite ici. Le -Werror=suggest-override
n'ignore pas cela (comme il se doit, puisque le override
est redondant dans ce cas)
Mais c'est plus compliqué que ça ... Si vous écrivez
virtual void f() final {...}
Cela signifie une chose complètement différente de celle
virtual void f() override final {...}
Le premier cas n'a pas besoin de remplacer quoi que ce soit! Le second le fait.
Je suppose donc que la vérification GCC est implémentée de cette façon (c'est-à-dire pour accepter parfois le override
redondant) afin de bien régler le dernier cas. Mais cela ne fonctionne pas bien, par exemple avec clang-tidy, qui supprimera correctement le remplacement lorsque la finale est suffisante (mais la compilation GCC échouera ...)