C++ : le mot clé override
Rédigé par Nicolas K Aucun commentaireL’un des paradigmes incontournables du C++, c’est bien la programmation orientée objet. Mais mal l’utiliser peut vite mener à des comportements inexpliqués et/ou à des erreurs fatales.
Dans ce tuto, nous allons voir comment se protéger de quelques erreurs en utilisant le mot-clé override
, un mot-clé apparu en C++11 et qui se révèle bien pratique pour éviter des erreurs bêtes qui font perdre un peu la tête !
Petit exercice
Pour commencer, une petite question. Qu’affiche le code suivant ?
#include <iostream>
class A {
public:
virtual char getValue() const {
return 'a';
}
virtual ~A() {}
};
class B : public A {
public:
virtual char getValue() {
return 'b';
}
};
int main() {
A* a = new B();
std::cout << a->getValue() << std::endl;
delete a;
}
Vous pensez qu’il affiche 'b' ? Mauvaise réponse. Testez.
Vous pensez qu’il affiche 'a' ? Très bien, vous vous êtes déjà fait avoir ?
Réponse
Ce code affiche effectivement 'a'. Mais on peut facilement se dire que celui qui a écrit ce code n’avait pas nécessairement ce résultat en tête. Et pourtant, l’explication est simple : la méthode virtual char A::getValue() const
et la méthode virtual char B::getValue()
n’ont pas la même signature : la première est const, l’autre non.
La méthode de B n’est donc pas une redéfinition comme on pourrait le vouloir mais simplement une surcharge. Pas de polymorphisme ici !
Maintenant, peut-être que vous aviez repéré cette subtilité. Peut-être que vous le savez et que vous ne vous seriez pas fait avoir. Mais un code évolue. Peut-être a-t-on ajouté const
après la création de la classe fille, en oubliant de la modifier en conséquence ? Peut-être A fait-elle partie d’une bibliothèque qui a évolué de son côté. Dans tous les cas, on arrive à cette erreur. Le pire dans l’histoire ? Ça compile parfaitement.
Éviter ce type d’erreur
La solution à ce problème ? Le mot-clé override
. Il permet de définir dans une classe fille que la méthode sur laquelle il s’applique redéfinit une méthode d’une classe mère.
Un exemple vaut mieux qu’un long discours :
class B : public A {
public:
virtual char getValue() override {
return 'b';
}
};
Avec ce code, on exprime clairement que la méthode est une redéfinition de la méthode de la classe mère. Si la signature est identique, le code compile. Par contre, si elle diffère comme c’est le cas avec notre classe A actuelle, on obtient cette fois une erreur à la compilation :
main.cpp:13:22: error: 'virtual char B::getValue()' marked 'override', but does not override
On remarque ainsi dès la compilation qu’on a fait une erreur (ou que la classe A a évolué et que la classe fille doit donc prendre en compte cette évolution).
Conclusion
Un conseil :
override
sur les méthodes qui redéfinissent une méthode d’une classe mère.Pour information, lorsqu’on utilise le mot-clé override
, le mot-clé virtual
n’est plus indispensable. Le code suivant fonctionne donc également :
char getValue() override {
return 'b';
}
C’est intéressant de le savoir, mais personnellement je préfère garder le mot clé virtual
pour que la redéfinition saute mieux aux yeux.