Reputation: 35285
I have 2 classes Base and Derived (derived publically from Base). When I write -
Derived * d1 = new Derived;
delete d1;
Compiler sees that d1 is a Derived type object. So it calls the derived class constructor (which calls the base class constructor). I have 2 questions here -
1) Why do we follow this order?
2) How do these constructors work together to allocate memory? I need some implementation details
Now the next statement is delete d1. So compiler sees that d1 is a derived type object and so calls the destuctor of derived class (which calls the destructor of base class after deleting the derived class members). I have one question here -
1) How do these destructors work together? Lets say the derived class destructor is passed the address of d1 in memory. How do these destructors free up the space now?
Upvotes: 2
Views: 1367
Reputation: 179981
(1) The base class does not depend on the derived class, but the other way around is possible. I.e. a Base
class cannot know which fields any Derived
class has, so Base::Base
won't and can't touch them. The other way around is possible, Derived::Derived
can access Base::member
. Therefore, Base::member
is initialized by Base::Base
before Derived::Derived gets the chance to use
Base::member`.
(2) constructors don't allocate memory. That's new
's task. Or if the object is a global, the compilers'. The constructor is called with this
already pointing to the allocated memory; it need just fill in the members at that location.
In the case of a base and derived constructor, one common implementation inserts the call to the Base constructor in the generated code for the Derived constructor. With single inheritance, the Base and Derived class usually share the same this
pointer, so the Derived constrcutor can then pass the same pointer that it got.
(1) [sic] Just like constructors don't allocate memory, destructors don't free it. That's the task of delete
- and again, for globals the compiler would do it.
Upvotes: 1
Reputation: 11648
While in inheritance, the compiler should know what it is inheriting. It should know what the Base
class consists of. It cannot inherit from a class, which it doesn't have any idea..
So, it does make sense that the Base
class constructor is called first and then the Derived
.
And in the case of Destruction, if the Base
destructor is being called first and gets destructed, the Derived
class may still be using the Base class members which becomes invalid.. Hence the Destruction is the exact inverse of the construction..
Upvotes: 0
Reputation: 70333
1) By default, the base class constructor is called automatically. However, the derived constructor is allowed to call the base class constructor explicitly in its initializer list. This would not be possible if the constructors were not executed derived-class-first.
Derived::Derived() : foo( 42 ), bar( 7 ), Base( 1, 2 ) { }
2) The compiler knows the memory footprint of the derived class (as all member variables are known at compile time), and allocates enough memory to hold both the base class and the derived class members. Details on the memory layout are specified by the ABI used by your system.
3) Destructors do more than just freeing up the memory. Actually, the destructors do not free up memory required to hold any member variables - only, where necessary, memory that member pointers point to.
Upvotes: 2
Reputation: 39916
When constructing, constructors are called from the highest base class until the oneof the most derived, which will be called the latest.
When destructors are called, it's the reverse order. First is called the destuctor of the most derived, until the one of the highest base class.
Upvotes: 0
Reputation: 116714
The code example you give wouldn't compile. delete
works on pointers, not objects.
I don't think C++ itself (the language standard) says anything about how memory is used to represent instances of types that use inheritance. However, in most implementations a single chunk of memory is allocated from the free store that is large enough to hold all the data of Base
and Derived
. When an instance of Derived
is deleted, both constructors run and then the single memory block is freed.
Similarly, if an instance of Derived
is an embedded data member of some class Container
, then the memory block that holds an instance of Container
will be made large enough to hold Derived
(and hence Base
) and all the other data of Container
.
Upvotes: 1
Reputation: 399949
That code will not compile. You cannot delete
an automatic instance, you must use new
to allocate the instance in order to use delete
on it.
When it comes to constructor order, I guess it just makes sense to run them so that more specialized classes can depend on the more general parts having already been done.
The memory layout of each class is known by the compiler, from inspecting the complete class declaration and recursing up through any and all superclasses.
Upvotes: 2