Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Constructor/Destructor inheritance

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?

like image 287
Jonathan H Avatar asked Jan 06 '13 16:01

Jonathan H


People also ask

Are constructors and destructors inherited?

Constructors and destuctors are not members of the class and not inherited but instead automatically invoked if the sub class has no constructor. up to now this excludes c++ which supports constructor inheritance. It's Me As of now only option 1 is right i.e destructors cannot be inherited.

How are constructor and destructor executed in inheritance?

In inheritance, the order of constructors execution is: from parent class to child class (parent -> class). 3. In inheritance, the order of destructors calling is: from child class to parent class (child -> parent).

Why constructor and destructor are not inherited?

Constructors are different from other class methods in that they create new objects, whereas other methods are invoked by existing objects. This is one reason constructors aren't inherited.

Do destructors get inherited?

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.


6 Answers

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.

like image 177
Kos Avatar answered Oct 05 '22 02:10

Kos


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 explicitly defining a constructor for the derived class, is that correct?

Other than the trivial case where you've defined a default constructor in the superclass, yes you are correct.


Q2: Can anybody who thinks it's not inherited please explain that?

This may be a matter of definitions of terminology. Whilst it's clear that virtual destructors exist and work "as expected", we see in the C++ standard ([class.virtual]):

Even though destructors are not inherited, a destructor in a derived class overrides a base class destructor declared virtual

(emphasis mine)


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

If you don't explicitly invoke a specific superclass constructor, then the default superclass constructor will be called (assuming it's visible).

like image 29
Oliver Charlesworth Avatar answered Oct 01 '22 02:10

Oliver Charlesworth


Destructors are not inherited. If a class doesn't define one, the compiler generates one. For trivial cases that destructor just calls the base class' destructor, and often that means that there is no explicit code for its destructor (which imitates inheritance). But if a class has members with destructors, the generated destructor calls destructors for those members before calling the base class' destructor. That's something that an inherited function would not do.

like image 36
Pete Becker Avatar answered Oct 04 '22 02:10

Pete Becker


Inheritance is what : mechanism of reusing and extending existing classes without modifying them, thus producing hierarchical relationships between them.

Inheritance is almost like embedding an object into a class.

when class is inheriting a base class then the base class's constructor is called first then derived class's ,and the destructor's call is in reverse order.

So Why Base Class Constructor is called (called not inherited may be with parameters/default) : to guarantees that the base class is properly constructed when the constructor for the derived class is executed.

Now Calling of Destructor (calling not inherit) : when base object get out of scope then the destructor is called on its own.so there is np issue of inheritance of destructor.

now your questions:

ans 1 - yes you are correct for first question.
ans 2 - so destructor is called not inherited after the scope of object goes out.
& ans 3 - if in derived class you are giving the call with parameters then only that constructor would get called , with it no other constructor would get called.
there is no point of issuse that 2 constructor of same object would get called on object creation,as constructor called at the creation of an object. It prepares the new object for use.so there is no logic of preparing the object twice with different constructors.

like image 30
sourcecode Avatar answered Oct 04 '22 02:10

sourcecode


Technically, destructors ARE inherited. But in normal circumstances, the inherited destructors are not directly used for a derived class; they're invoked because the derived class's own destructor calls them in order to destroy its own "base class subobjects" as a step within destroying the larger object. And in the unusual circumstances where you do directly use a base class destructor on a derived object, it's very difficult to avoid Undefined Behavior.

This example comes straight from the C++ Standard (12.4p12).

struct B {
  virtual ~B() { }
};
struct D : B {
  ~D() { }
};

D D_object;
typedef B B_alias;
B* B_ptr = &D_object;

void f() {
  D_object.B::~B();              // calls B's destructor
  B_ptr->~B();                   // calls D's destructor
  B_ptr->~B_alias();             // calls D's destructor
  B_ptr->B_alias::~B();          // calls B's destructor
  B_ptr->B_alias::~B_alias();    // calls B's destructor
}

If ~B were not an inherited member of D, the first statement in f would be ill-formed. As it is, it's legal C++, though extremely dangerous.

like image 35
aschepler Avatar answered Oct 02 '22 02:10

aschepler


In your example, you're explicitly calling the destructor functions. This is legal (obviously, since it compiled and ran) but almost always incorrect.

For dynamically-allocated objects created with new, the destructor will be run when the objected is removed with delete.

For statically-allocated objects, which are created simply by declaring the object within the scope of a function, the destructor is run when the object's scope disappears. That is, when main() exits, the objects' destructors will be run. But you've already run the destructors for those objects by calling them manually! This is why your example's output shows the count decreasing to -3... you've run the destructors for a, b, and c twice.

Here's the same code, annotated to show when destructors will be automatically run:

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;   // Implicitly calls destructor for a_ptr.  a_ptr is class B,
       // so it would call a_ptr->~B() if it existed. Because B is an A, after
       // its destructor is called, it calls the superclass's destructor,
       // a_ptr->~A().

    printf("Create C\n"); C c;
    printf("Delete C\n"); c.~C();
}
// Function exits here at the close brace, so anything declared in its scope is
// deallocated from the stack and their destructors run.
// First `c` is destroyed, which calls c.~C(), then because C is a subclass of A
// calls c.~B() (which doesn't exist, so a blank implementation is used), then
// because B is a subclass of A calls c.~A().  This decrements the counter, but
// the count is wrong because you already manually called c.~C(), which you
// ordinarily shouldn't have done.
// Then `b` is destroyed, in a similar manner.  Now the count is off by 2,
// because you had already called b.~B().
// Lastly `a` is destroyed, just as above.  And again, because you had already
// called a.~A(), the count is now off by 3.
like image 44
BigPeteB Avatar answered Oct 05 '22 02:10

BigPeteB