Doit-on passer à delete le même pointeur que celui renvoyé par new, ou peut-on lui passer un pointeur vers l'un des types de base de la classe ? Par exemple :
class Base
{
public:
virtual ~Base();
...
};
class IFoo
{
public:
virtual ~IFoo() {}
virtual void DoSomething() = 0;
};
class Bar : public Base, public IFoo
{
public:
virtual ~Bar();
void DoSomething();
...
};
Bar * pBar = new Bar;
IFoo * pFoo = pBar;
delete pFoo;
Bien sûr, cela est grandement simplifié. Ce que je veux vraiment faire, c'est créer un conteneur rempli de boost::shared_ptr et le passer à un code qui le retirera du conteneur lorsqu'il aura terminé. Ce code ne saura rien de l'implémentation de Bar ou de Base, et comptera sur l'opérateur de suppression implicite dans le destructeur de shared_ptr pour faire ce qu'il faut.
Est-ce que cela peut fonctionner ? Mon intuition me dit que non, puisque les pointeurs n'auront pas la même adresse. D'un autre côté, un dynamic_cast<Bar*> devrait fonctionner, donc quelque part le compilateur stocke suffisamment d'informations pour le faire.
Merci pour l'aide, à tous ceux qui ont répondu et commenté. Je connaissais déjà l'importance des destructeurs virtuels, comme le montre mon exemple ; après avoir vu la réponse, j'y ai réfléchi un peu, et j'ai réalisé que le raison entière pour un destructeur virtuel est ce scénario exact. Il fallait donc que cela fonctionne. J'ai été déconcerté par l'absence d'un moyen visible de reconvertir le pointeur vers l'original. Un peu plus de réflexion m'a amené à croire qu'il y avait un moyen invisible, et j'ai supposé que le destructeur retournait le vrai pointeur pour que delete le libère. L'examen du code compilé de Microsoft VC++ a confirmé mes soupçons lorsque j'ai vu cette ligne dans ~Base :
mov eax, DWORD PTR _this$[ebp]
Le suivi de l'assembleur a révélé qu'il s'agissait du pointeur transmis à la fonction de suppression. Mystère résolu.
J'ai corrigé l'exemple pour ajouter le destructeur virtuel à IFoo, c'était un simple oubli. Merci encore à tous ceux qui l'ont signalé.