C++ Constructor/Destructor inheritance

Jonathan H picture Jonathan H · Jan 6, 2013 · Viewed 80.3k times · Source

EDIT : Summary of answers

In the following, B is a subclass of A.

It's a matter of terminology; ctors and dtors are not inherited, in the sense that the ctor/dtor of B will not be borrowed from A's interface. A class has at least one constructor, and has exactly one destructor.

  • Constructors:
    • B does not inherit constructors from A;
    • Unless B's ctor explicitely calls one of A's ctor, the default ctor from A will be called automatically before B's ctor body (the idea being that A needs to be initialized before B gets created).
  • Destructors:
    • B does not inherit A's dtor;
    • After it exits, B's destructor will automatically call A's destructor.

Acknowledgements: I would like to thank especially Oli Charlesworth and Kos for their answers, I set Kos' answer as the solution because it was the one I understood best.


ORIGINAL POST

When you search for "C++ destructor inheritance site:stackoverflow.com" on Google, you currently find the following posts:

  1. Constructor and Destructor Inheritance: two users with 30k+ reputation say that it is inherited, and that it's not
  2. Are virtual destructors inherited?: here nothing is mentioned that would point to destructors not being inherited
  3. Destructors and inheritance in C++?: The comments seem to indicate the destructors are inherited

Q1: What I also know from practice, is that you cannot initialize a derived object with the same prototype than it's parent constructor without explicitely defining a constructor for the derived class, is that correct?


Even though it's rather clear from the posts that destructors seem to be inherited, I'm still puzzled by the fact that a user with 32k reputation would say its not. I wrote a little example that should clarify everyone's mind:

#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();

}

and here is the output (compiled with 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: Can anybody who thinks it's not inherited please explain that?

Q3: So what happens when you call the constructor of a subclass with inputs? Is the "empty constructor" of the superclass called as well?

Answer

Kos picture Kos · Jan 6, 2013

Terminology, terminology...

OK, what do we mean by "Foo is inherited"? We mean that if objects of class A have Foo in its interface, then objects of class B which is a subclass of A also have Foo in its interface.

  • Constructors aren't a part of objects' interface. They belong directly to classes. Classes A and B may provide completely different sets of constructors. No "being inherited" here.

    (Implementation detail: each B's constructors calls some A's constructor.)

  • Destructors indeed are a part of each object's interface, since the object's user is responsible for calling them (i.e. directly with delete or indirectly by letting an object out of scope). Each object has exactly one destructor: its own destructor, which might optionally be a virtual one. It is always its own, and it's not inherited.

    (Implementation detail: B's destructor calls A's destructor.)

So: there's a connection between base and derived constructors and destructors, but it's not like "they're inherited".

I hope this answers what you have in mind.