You are here:

C++/Initialization order in c

Advertisement


Question
Hi,

Could you please tell that why the constructor the of base is called first? Is there any technical reson behind it or just it happens because stroupstrup wanted to do so.

Thanks!

Answer
Consider: "Why do we construct the base of a skyscraper first? Is there a technical reason or is it just because the construction company wanted to do so?"

Very little if anything that is mandated in the C++ standard is done on the whim of Bjarne Stroustrup or any other C++ committee member. A lot of such mandates have to do with what can be done (or was thought to be doable at the time) and ensuring that programmers can rely on behaviour between C++ implementations. Remember that anything mandated in the standard has to be technically possible to achieve - preferable without too much difficulty or overhead. It also has to ensure that all facets related to the area of mandate are catered for. They did not always get it correct. Some things have proved easier to deal with than originally thought (detecting whether >> meant a shift operator or nested template specialisations for example - the standard requires a space between > when closing template parameter lists: > >) and others more difficult (efficient throw specification implementations and exported templates for example).

First let's clarify what the class object initialisation order is:

The first parts of a class to be constructed are any virtual base classes, and this _only_ occurs for the "most derived class".

Next direct base classes are constructed, and this applies to each base class recursively.

Then non-static data members are initialised.

Finally the body of the constructor is executed.

Base classes are initialised in the order they appear in the base class specifier list of the class definition and data members are initialised in the order they are declared in the class definition. Note: the order items appear in a constructor initialiser list is irrelevant here. The reason for this mandated ordering is to ensure that the object is always destroyed in the reverse order it was initialised in, otherwise different constructors could cause different initialisation orderings, thus preventing a guaranteed reverse destruction order.

The obvious intent is that by the time a derived class constructor executes all its base and member sub-objects have already been constructed and so are usable. An object (or sub-object) is not useable until it has been constructed. This is good for us C++ programmers as we know what we can rely on. Writing constructors would be a lot less simple if such orderings were not laid down.

Likewise we know that by the time we start initialising data members all the base class sub-objects have been defined. You can call member functions during construction. However doing so before all base classes have been initialised results in undefined behaviour. This probably has to do with behind the scenes setting up of offsets etc. for the this pointer and maybe sub-objects. The this pointer value can change depending on the type of the pointer at the time, particularly when multiple inheritance is used. The way such nastiness is handled differs from compiler to compiler. As such the standard cannot predict the behaviour so states the effect is undefined.

One area that has to occur in the mandated order of base class construction has to do with virtual function overriding. If we have three classes B, D and MD (for Base, Derived and Most Derived) and B declares a virtual member function VFn that is overridden by D and by MD then these overrides are fixed up for D and MD during construction. Typically each class (note: class _not_ object) that has virtual member functions has an associated structure called a vtable. This contains the pointers to the virtual member functions. When we construct a B then we use the B vtable containing a pointer to B::VFn. When we construct a D we use the D vtable containing a pointer to D::VFn. When we construct a MD we use the MD vtable containing a pointer to MD::VFn. So when we construct a MD object the following happened:

MD will cause D to be constructed, but D is derived from B so this causes B to be constructed, using the B vtable.

Next D is constructed and the D vtable is in effect.

Finally MD is constructed and the MD vtable is used.

Note that the reverse happens during destruction. Note also that the exact details used by real compilers may differ (I suspect things get complicated in the light of things such as multiple inheritance - again!) but the above is good enough to give you the basic idea.

If the base classes were executed in any other order then either the D or B vtables would be in effect after construction completes so a call to VFn() would call D::VFn or B::VFn, i.e. the wrong override would get called.

You probably noticed that during calls to base class constructors the vtable in effect is for the base class under construction so overrides for that base class are called which is not necessarily that of the most derived class. A similar effect exists during destruction. This is noted in the C++ standard in section 12.7 paragraph 3. Similar effects occur when using dynamic_cast and typeid during construction and destruction as RTTI information is typically stored in the vtable (implying that types used with these features require a vtable).

The following program demonstrates the effect of calling virtual functions during construction and destruction:

#include <iostream>

class B
{
public:
   B()
   {
       std::cout << "Executing B::B(), calling VFn:\n";
       VFn();
   }

   virtual ~B()
   {
       std::cout << "Executing B::~B(), calling VFn:\n";
       VFn();
   }

   virtual void VFn()
   {
       std::cout << "   Executing B::VFn()\n";
   }
};

class D : public B
{
public:
   D()
   {
       std::cout << "Executing D::D(), calling VFn:\n";
        VFn();
   }

   ~D()
   {
       std::cout << "Executing D::~D(), calling VFn:\n";
       VFn();
   }

   void VFn()
   {
       std::cout << "   Executing D::VFn()\n";
   }
};

class MD : public D
{
public:
   MD()
   {
       std::cout << "Executing MD::MD(), calling VFn:\n";
        VFn();
   }

   ~MD()
   {
       std::cout << "Executing MD::~MD(), calling VFn:\n";
       VFn();
   }

   void VFn()
   {
       std::cout << "   Executing MD::VFn()\n";
   }
};

int main()
{
   MD md;
}

Hope this has given you a glimpse into the sort of detail that the C++ standard has to cope with.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.