C++ : le mot clé override

Rédigé par Nicolas K Aucun commentaire

L’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 :

Toujours utiliser 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.

Classé dans : Tutos Mots clés : aucun

Écrire un commentaire

Quelle est la troisième lettre du mot pbuj ?

Fil RSS des commentaires de cet article