EDIT : Résumé des réponses
Dans ce qui suit, B est une sous-classe de A.
C'est une question de terminologie ; les ctors et les dtors sont pas hérité, dans le sens où le ctor/dtor de B sera pas être emprunté à l'interface de A. Une classe a au moins un constructeur, et a exactement un destructeur.
-
Constructeurs :
- B n'hérite pas des constructeurs de A ;
- Sauf si le ctor de B appelle explicitement l'un des le ctor de A, le ctor par défaut de A sera appelé automatiquement antes de le corps du ctor de B (l'idée étant que A doit être initialisé avant que B ne soit créé).
-
Destructeurs :
- B n'hérite pas du dtor de A ;
- Après il sort, le destructeur de B appellera automatiquement le destructeur de A.
Remerciements : Je tiens à remercier tout particulièrement Oli Charlesworth et Kos pour leurs réponses. J'ai choisi la réponse de Kos comme solution car c'est celle que j'ai le mieux comprise.
POSTE ORIGINAL
Lorsque vous recherchez "C++ destructor inheritance site:stackoverflow.com" sur Google, vous trouvez actuellement les messages suivants :
- Héritage des constructeurs et des destructeurs deux utilisateurs avec 30k+ de réputation disent que c'est hérité, et que ce n'est pas le cas
- Les destructeurs virtuels sont-ils hérités ? : ici, rien n'est mentionné qui indiquerait que les destructeurs ne sont pas hérités.
- Destructeurs et héritage en C++ ? : Les commentaires semblent indiquer que les destructeurs sont hérités.
Q1 : Ce que je sais également de la pratique, c'est que vous ne pouvez pas initialiser un objet dérivé avec le même prototype que le constructeur de son parent sans définir explicitement un constructeur pour la classe dérivée, est-ce correct ?
Même s'il est assez clair, d'après les messages, que les destructeurs semblent être hérités, je suis toujours perplexe par le fait qu'un utilisateur avec 32k de réputation dise le contraire. J'ai écrit un petit exemple qui devrait clarifier l'esprit de chacun :
#include <cstdio>
/******************************/
// Base class
struct A
{
A() { printf( "\tInstance counter = %d (ctor)\n", ++instance_counter ); }
~A() { printf( "\tInstance counter = %d (dtor)\n", --instance_counter ); }
static int instance_counter;
};
// Inherited class with default ctor/dtor
class B : public A {};
// Inherited class with defined ctor/dtor
struct C : public A
{
C() { printf("\tC says hi!\n"); }
~C() { printf("\tC says bye!\n"); }
};
/******************************/
// Initialize counter
int A::instance_counter = 0;
/******************************/
// A few tests
int main()
{
printf("Create A\n"); A a;
printf("Delete A\n"); a.~A();
printf("Create B\n"); B b;
printf("Delete B\n"); b.~B();
printf("Create new B stored as A*\n"); A *a_ptr = new B();
printf("Delete previous pointer\n"); delete a_ptr;
printf("Create C\n"); C c;
printf("Delete C\n"); c.~C();
}
et voici le résultat (compilé avec g++ 4.4.3) :
Create A
Instance counter = 1 (ctor)
Delete A
Instance counter = 0 (dtor)
Create B
Instance counter = 1 (ctor)
Delete B
Instance counter = 0 (dtor)
Create new B stored as A*
Instance counter = 1 (ctor)
Delete previous pointer
Instance counter = 0 (dtor)
Create C
Instance counter = 1 (ctor)
C says hi!
Delete C
C says bye!
Instance counter = 0 (dtor) // We exit main() now
C says bye!
Instance counter = -1 (dtor)
Instance counter = -2 (dtor)
Instance counter = -3 (dtor)
Q2 : Ceux qui pensent que ce n'est pas un héritage peuvent-ils l'expliquer ?
Q3 : Alors que se passe-t-il lorsque vous appelez le constructeur d'une sous-classe avec des entrées ? Le "constructeur vide" de la superclasse est-il également appelé ?