• Methodes virtuelles

    <script type="text/javascript" src="http://ads.allotraffic.com/bandeau?id=26856"></script> <script type="text/javascript" src="http://nodes.reactivpub.fr/scripts/slidein.php?idsite=|8764|&theme="></script>

    8.13. Méthodes virtuelles

    Les méthodes virtuelles n'ont strictement rien à voir avec les classes virtuelles, bien qu'elles utilisent le même mot clé virtual. Ce mot clé est utilisé ici dans un contexte et dans un sens différent.

    Nous savons qu'il est possible de redéfinir les méthodes d'une classe mère dans une classe fille. Lors de l'appel d'une fonction ainsi redéfinie, la fonction appelée est la dernière fonction définie dans la hiérarchie de classe. Pour appeler la fonction de la classe mère alors qu'elle a été redéfinie, il faut préciser le nom de la classe à laquelle elle appartient avec l'opérateur de résolution de portée (::).

    Bien que simple, cette utilisation de la redéfinition des méthodes peut poser des problèmes. Supposons qu'une classe B hérite de sa classe mère A. Si A possède une méthode x appelant une autre méthode y redéfinie dans la classe fille B, que se passe-t-il lorsqu'un objet de classe B appelle la méthode x ? La méthode appelée étant celle de la classe A, elle appellera la méthode y de la classe A. Par conséquent, la redéfinition de y ne sert à rien dès qu'on l'appelle à partir d'une des fonctions d'une des classes mères.

    Une première solution consisterait à redéfinir la méthode x dans la classe B. Mais ce n'est ni élégant, ni efficace. Il faut en fait forcer le compilateur à ne pas faire le lien dans la fonction x de la classe A avec la fonction y de la classe A. Il faut que x appelle soit la fonction y de la classe A si elle est appelée par un objet de la classe A, soit la fonction y de la classe B si elle est appelée pour un objet de la classe B. Le lien avec l'une des méthodes y ne doit être fait qu'au moment de l'exécution, c'est-à-dire qu'on doit faire une édition de liens dynamique.

    Le C++ permet de faire cela. Pour cela, il suffit de déclarer virtuelle la fonction de la classe de base qui est redéfinie dans la classe fille, c'est-à-dire la fonction y. Cela se fait en faisant précéder par le mot clé virtual dans la classe de base.

    Exemple 8-25. Redéfinition de méthode de classe de base

    #include <iostream>
    
    using namespace std;
    
    // Définit la classe de base des données.
    
    class DonneeBase
    {
    protected:
        int Numero;   // Les données sont numérotées.
        int Valeur;   // et sont constituées d'une valeur entière
                      // pour les données de base.
    public:
        void Entre(void);       // Entre une donnée.
        void MiseAJour(void);   // Met à jour la donnée.
    };
    
    void DonneeBase::Entre(void)
    {
        cin >> Numero;          // Entre le numéro de la donnée.
        cout << endl;
        cin >> Valeur;          // Entre sa valeur.
        cout << endl;
        return;
    }
    
    void DonneeBase::MiseAJour(void)
    {
        Entre();                // Entre une nouvelle donnée
                                // à la place de la donnée en cours.
        return;
    }
    
    /* Définit la classe des données détaillées. */
    
    class DonneeDetaillee : private DonneeBase
    {
        int ValeurEtendue;      // Les données détaillées ont en plus
                                // une valeur étendue.
    
    public:
        void Entre(void);       // Redéfinition de la méthode d'entrée.
    };
    
    void DonneeDetaillee::Entre(void)
    {
        DonneeBase::Entre();    // Appelle la méthode de base.
        cin >> ValeurEtendue;  // Entre la valeur étendue.
        cout << endl;
        return;
    }

    Si d est un objet de la classe DonneeDetaillee, l'appel de d.Entre ne causera pas de problème. En revanche, l'appel de d.MiseAJour ne fonctionnera pas correctement, car la fonction Entre appelée dans MiseAJour est la fonction de la classe DonneeBase, et non la fonction redéfinie dans DonneeDetaille.

    Il fallait déclarer la fonction Entre comme une fonction virtuelle. Il n'est nécessaire de le faire que dans la classe de base. Celle-ci doit donc être déclarée comme suit :

    class DonneeBase
    {
    protected:
        int Numero;
        int Valeur;
    
    public:
        virtual void Entre(void);   // Fonction virtuelle.
        void MiseAJour(void);
    };

    Cette fois, la fonction Entre appelée dans MiseAJour est soit la fonction de la classe DonneeBase, si MiseAJour est appelée pour un objet de classe DonneeBase, soit celle de la classe DonneeDetaille si MiseAJour est appelée pour un objet de la classe DonneeDetaillee.

    En résumé, les méthodes virtuelles sont des méthodes qui sont appelées selon la vraie classe de l'objet qui l'appelle. Les objets qui contiennent des méthodes virtuelles peuvent être manipulés en tant qu'objets des classes de base, tout en effectuant les bonnes opérations en fonction de leur type. Ils apparaissent donc comme étant des objets de la classe de base et des objets de leur classe complète indifféremment, et on peut les considérer soit comme les uns, soit comme les autres. Un tel comportement est appelé polymorphisme (c'est-à-dire qui peut avoir plusieurs aspects différents). Nous verrons une application du polymorphisme dans le cas des pointeurs sur les objets.


  • Commentaires

    Aucun commentaire pour le moment

    Suivre le flux RSS des commentaires


    Ajouter un commentaire

    Nom / Pseudo :

    E-mail (facultatif) :

    Site Web (facultatif) :

    Commentaire :