[23] Héritage - ce que l'on ne vous a jamais dit

(Une partie de C++ FAQ Lite fr, Copyright © 1991-2002, Marshall Cline, cline@parashift.com)

Traduit de l'anglais par Stéphane Bailliez

Les FAQs de la section [23]


[23.1] Is it okay for a non-virtual function of the base class to call a virtual function?
Yes. It's sometimes (not always!) a great idea. For example, suppose all Shape objects have a common algorithm for printing, but this algorithm depends on their area and they all have a potentially different way to compute their area. In this case Shape's area() method would necessarily have to be virtual (probably pure virtual) but Shape::print() could, if we were guaranteed no derived class wanted a different algorithm for printing , be a non-virtual defined in the base class Shape.
#include "Shape.hpp"

void Shape::print() const
{
	float a = this->area();  // area() is pure virtual
	...
}

[ Haut | Bas | Rechercher ]


[23.2] Pourquoi l'appel d'une méthode virtuelle dans le constructeur de la classe de base n'invoque t'elle pas la fonction virtuelle surchargée de ma classe dérivée?
Au sein du constructeur de la classe Base, l'objet n'est pas encore un Derived, donc si Base::Base()appelle une fonction virtuellevirt(), la fonction Base::virt()sera celle effectivement appelée, même si Derived::virt()existe.

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 ]


[23.3] Est ce qu'une classe dérivée peut remplacer ("overrider") une fonction non virtuelle de la classe de base?
Cela est légal, mais pas trés moral..

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 ]


[23.4] Quelle est la signification de, Warning: Derived::f(float) hides Base::f(int)?
Cela signifie que vous allez mourir.

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 ]


[23.5] Quelle est la signification du message me disant que la "virtual table" est un "unresolved external"?
Si vous avez une erreur de link de la forme: "Error: Unresolved or undefined symbols detected: virtual table for class Fred," vous avez probablement une méthode virtuellenon définie dans la classe Fred.

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 ]


E-mail Marshall Cline 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