Question

I just read in this answer that if you have the following code

class Base
{
    public Base()
    {

    }
}

class One : Base
{
    string test = "text";
}

class Two : Base
{
    string test;
    public Two()
    {
        test = "text";
    }
}

For class One the initializaton One.test will be initalized before Base::Base is called. But Two.test will be initialized after Base::Base is called.

I assume this is because in both cases it is

  1. fields <- this includes One.test
  2. Base::Base()
  3. One::One() or Two::Two() <- which initializes Two.test

I think I remember that initialization lists are just before the constructor. So is the initialization order then:

  1. fields
  2. base initializer list
  3. base constructor
  4. own initializer list
  5. own constructor

And where do the fields of Base come in? Are all fields initialized first when memory is allocated or just before the initialization list of the current base class?

And are there other steps in the list you can think of?

I would appreciate if somebody could give a good overview.

Was it helpful?

Solution

C++ initialization takes place in this order:

  1. Base classes, from left to right
  2. Member variables, in the order in which they are declared

The initialization of base classes from step 1 recursively takes the same steps. Therefore, all bases are fully constructed before any member variable initialization takes place, and before the body of the constructor begins execution.

Therefore, when the compiler encounters:

Two two;

First, Two::Two begins execution, starting with the initializer list. All bases are initialized via the initialization list, even if you haven't written one or left out the initialization of a base class. So, the code that actually runs looks more like this:

Two::Two
:
  One(),
  test()
{
  test = "text";
}

The initializer list is executed before the body of the constructor. Therefore, One is completely constructed before the the body of Two::Two begins execution.

In turn, One looks like this:

One::One()
: 
  Base()
{
  string test = "test";
}

And Base is empty:

Base::Base()
{
}

So what happens when Two two; is executed is:

  1. Base is constructed.
  2. One is constructed
  3. The automatic variable test is constructed, initialized, and destroyed in the context of One::One
  4. Two::test is default-initialized
  5. Two::test is assigned the value "text"

Note that some of this, especially steps 4 & 5 might get optimized by the compiler if it thinks it's safe to do so.

OTHER TIPS

For class One the initializaton One.test will be initalized before Base::Base is called. But Two.test will be initialized after Base::Base is called.

No. Bases are initialized before any member.

In the simplified (and yet most common) case of no virtual bases, the order of initialization of the objects is: bases in the order in which they appear in the class declaration, then members in the order in which they appear in the declaration (not the initialization list). Only after that completes, the body of the constructor is entered.

Virtual bases are initialized before any other base, in an other that is determined by a depth first search going from the first to the last declared base.

In the case of Two there is one detail that probably matters and I am not sure you are aware, the member test is initialized in the initializer list of Two, before entering the body of the constructor, and then it is assigned.

The others have answered the question.
But the following Demo may be useful.

#include <iostream>
class String
{
    public:
        String(char const* d)               {std::cout << "String Constructor: " << d << "\n";}
        String()                            {std::cout << "String Constructor: Default\n";}
        String(String const& rhs)           {std::cout << "String Constructor: Copy\n";}
        String& operator=(String const& rhs){std::cout << "String Assignment\n";}
        ~String()                           {std::cout << "String Destructor\n";}
};

class Base
{
    public: Base()
    {
        std::cout << "Base::Base()\n";
    }
};

class One : Base
{
    String test = "text";
};

class Two : Base
{
    String test;
    public: Two()
    {
        std::cout << "Two::Two\n";
        test = "text";
    }
};

int main()
{
    std::cout << "Trying One\n";
    One     one;

    std::cout << "==========\n\n\n";
    std::cout << "Trying Two\n";
    Two     two;

    std::cout << "==========\n\n\n";
    std::cout << "Trying Base\n";
    Base    b;
}

The result of this:

> ./a.out
Trying One                    // Outside the class about to start
Base::Base()                  // One: Calls the base constructor first Base
String Constructor: text      // One: Constructs its members.
==========


Trying Two                    // Outside the class about to start
Base::Base()                  // Two: Calls the base construtor first
String Constructor: Default   // Two: Constructs its members next
Two::Two                      // Two: Now entering the body of the constructor
String Constructor: text      //      Builds a string
String Assignment             //      Calls the assignment constructor.
String Destructor             //      Temporary destroyed.
==========                    //


Trying Base
Base::Base()
String Destructor             // Destroys the string in Two
String Destructor             // Destroys the string in One
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top