
Envoyé par
Mat007
Je lis :
Vous pouvez alors deviner ce que l'instruction delete a; provoque : la destruction d'un objet de type A, donc l'appel de A::~A(), et de rien d'autre.
C'est "divination" est inexacte (pour ne pas dire entièrement fausse) : en fait c'est un comportement indéfini.
Ce qui signifie qu'il faut absolument un destructeur virtuel dans ce cas, même si les destructeur de la classe dérivée ne fait "rien de plus" que celui de la classe de base.
En effet, c'est la virtualité du destructeur
- qui dit à 'delete' d'aller chercher l'adresse réelle de l'objet (l'adresse de l'objet complet), qui peut être différente de celle passée à delete;
- c'est aussi elle qui permet de trouver le bon opérateur delete membre si la classe dérivée en déclare un autre que la classe de base.
Sans destructeur virtuel, l'adresse passée à 'operator delete' (la fonction, pas l'expression 'delete') peut être incorrecte et corrompre le free-store (free-store = tas). En pratique, ce cas va se produire en cas d'héritage multiple (ou virtuel).
La phrase "la destruction d'un objet de type A, donc l'appel de A::~A(), et de rien d'autre." me parait donc inappropriée.
Pour un objet automatique (variable locale d'une fonction) ou global, il n'y a aucun problème de destruction parce que le compilateur connait toujours le type réel de l'objet. La règle du destructeur virtuel s'applique aux appels à delete, avec un pointeur sur une classe de base de l'objet créé (type différent de celui utilisé avec 'new') :
1 2
| Base *bp = new Derived;
delete bp; // le destructeur DOIT être virtuel |
La règle s'applique aussi aux appels explicites au destructeur :
1 2 3 4
| Base *bp = new Derived;
bp->~Base (); // le destructeur DOIT être virtuel
// mais pourquoi voudriez-vous faire cela?
// Ceci n'est PAS une incitation. |
J'insiste peut-être lourdement, parce que la FAQ traite la chose trop à la légère AMA.
Partager