#include "Shape.hpp" void Shape::print() const { float a = this->area(); // area() is pure virtual ... }
[ Haut | Bas | Rechercher ]
De manière analogue, au sein du destructeur de Base, l'objet n'est plus un objet Derived, donc si Base::~Base() appelle virt(), la fonction Base::virt() sera appelée, et non pas la fonction surchargée Derived::virt().
Vous allez rapidement voir le sagesse de cette approche lorsque vous verrez le désastre si Derived::virt() touche à un objet membre de la classe Derived. En particulier, si Base::Base() appelle la fonction virtuelle virt(), cette règle implique que Base::virt() sera appelé. Si il n'y avait pas cette règle, Derived::virt() aurait été appelé avant que la partie Derived de l'objet Derived soit construit, et Derived::virt() pourrait toucher des objets membres de la partie Derived de l'objet Derived. Cela pourrait être un désastre.
[ Haut | Bas | Rechercher ]
Des programmeurs C++ expérimentés peuvent parfois redéfinir une fonction non virtuelle pour une question d'efficacité (e.g., si l'implémentation de la classe dérivée peut faire une meilleure utilisation de ses ressources) ou pour circonvenir aux problèmes des méthodes cachées. Cependant du point de vue client, les effets doivent être identiques car les fonctions non virtuelles sont dispatchées suivant le type statique de pointeur/référence plutôt que sur le type dynamique de l'objet pointé/référencé.
[ Haut | Bas | Rechercher ]
Voilà le problème auquel vous êtes confronté: si Base déclare une fonction membre f(int), et Derived déclare une fonction membre f(float) (même nom, mais paramètres de type et/ou de constness différents), alors la Base::f(int) est "cachée" plutôt que surchargée (et ce même si Base::f(int) est virtuelle)
Voici comment vous pouvez vous en sortir: Derived doit avoir une déclaration using de la fonction membre cachée. Par exemple,
class Base {
public:
void f(int);
};
class Derived : public Base {
public:
using
Base::f; // ne cache plus Base::f(int)
void f(double);
};
Si la syntaxe using n'est pas supportée par votre compilateur, redéfinissez les fonctions membres cachées de la classe de Base, et ce même si elle ne sont pas virtuelles. Normalement, cette redéfinition doit appeler la fonction de la classe Base en utilisant l'opérateur de portée ::. E.g.,
class
Derived : public Base {
public:
void
f(double);
void
f(int i) { Base::f(i); } // cette redéfinition appelle
Base::f(int)
};
[ Haut | Bas | Rechercher ]
Typiquement, le compilateur crée une structure données appelée "table virtuelle"(virtual table) pour les classes ayant des fonctions virtuelles (voir la méthode de gestion dans dynamic binding). Normallement vous n'avez pas à vous en soucier, mais si vous oubliez de définir une fonction virtuelle pour la class Fred, vous aurez parfois ce genre d'erreur lors de l'édition des liens.
Pour en venir au fond du problème, une grande quantité de compilateurs place cette "table virtuelle" dans l'unité de compilation qui défini la première fonction virtuelle non inline de la classe. Donc, si la premiere fonction virtuelle non-inline de la classe Fred est wilma(), le compilateur mettra la table virtuelle de Fred dans la même unité de compilation qui voit Fred::wilma(). Malheureusement si vous oubliez de définir Fred::wilma(), plutôt que d'obtenir un "Fred::wilma() is undefined", vous obtiendrez un "Fred's virtual table is undefined".
[ Haut | Bas | Rechercher ]
Ecrire à l'auteur,
au traducteur,
ou en savoir plus sur la traduction.
C++ FAQ Lite fr |
Table des matières |
Index |
A propos de l'auteur |
© |
Téléchargez votre propre copie ]
Dernière révision Sun Apr 13 23:54:38 PDT 2003