[c++] What are the rules for calling the superclass constructor?

What are the C++ rules for calling the superclass constructor from a subclass one?

For example, I know in Java, you must do it as the first line of the subclass constructor (and if you don't, an implicit call to a no-arg super constructor is assumed - giving you a compile error if that's missing).

This question is related to c++ inheritance constructor

The answer is


Everybody mentioned a constructor call through an initialization list, but nobody said that a parent class's constructor can be called explicitly from the derived member's constructor's body. See the question Calling a constructor of the base class from a subclass' constructor body, for example. The point is that if you use an explicit call to a parent class or super class constructor in the body of a derived class, this is actually just creating an instance of the parent class and it is not invoking the parent class constructor on the derived object. The only way to invoke a parent class or super class constructor on a derived class' object is through the initialization list and not in the derived class constructor body. So maybe it should not be called a "superclass constructor call". I put this answer here because somebody might get confused (as I did).


In C++, the no-argument constructors for all superclasses and member variables are called for you, before entering your constructor. If you want to pass them arguments, there is a separate syntax for this called "constructor chaining", which looks like this:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

If anything run at this point throws, the bases/members which had previously completed construction have their destructors called and the exception is rethrown to to the caller. If you want to catch exceptions during chaining, you must use a function try block:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

In this form, note that the try block is the body of the function, rather than being inside the body of the function; this allows it to catch exceptions thrown by implicit or explicit member and base class initializations, as well as during the body of the function. However, if a function catch block does not throw a different exception, the runtime will rethrow the original error; exceptions during initialization cannot be ignored.


The only way to pass values to a parent constructor is through an initialization list. The initilization list is implemented with a : and then a list of classes and the values to be passed to that classes constructor.

Class2::Class2(string id) : Class1(id) {
....
}

Also remember that if you have a constructor that takes no parameters on the parent class, it will be called automatically prior to the child constructor executing.


CDerived::CDerived()
: CBase(...), iCount(0)  //this is the initialisation list. You can initialise member variables here too. (e.g. iCount := 0)
    {
    //construct body
    }

Nobody mentioned the sequence of constructor calls when a class derives from multiple classes. The sequence is as mentioned while deriving the classes.


If you have default parameters in your base constructor the base class will be called automatically.

using namespace std;

class Base
{
    public:
    Base(int a=1) : _a(a) {}

    protected:
    int _a;
};

class Derived : public Base
{
  public:
  Derived() {}

  void printit() { cout << _a << endl; }
};

int main()
{
   Derived d;
   d.printit();
   return 0;
}

Output is: 1


If you have a constructor without arguments it will be called before the derived class constructor gets executed.

If you want to call a base-constructor with arguments you have to explicitly write that in the derived constructor like this:

class base
{
  public:
  base (int arg)
  {
  }
};

class derived : public base
{
  public:
  derived () : base (number)
  {
  }
};

You cannot construct a derived class without calling the parents constructor in C++. That either happens automatically if it's a non-arg C'tor, it happens if you call the derived constructor directly as shown above or your code won't compile.


In C++ there is a concept of constructor's initialization list, which is where you can and should call the base class' constructor and where you should also initialize the data members. The initialization list comes after the constructor signature following a colon, and before the body of the constructor. Let's say we have a class A:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

Then, assuming B has a constructor which takes an int, A's constructor may look like this:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

As you can see, the constructor of the base class is called in the initialization list. Initializing the data members in the initialization list, by the way, is preferable to assigning the values for b_, and c_ inside the body of the constructor, because you are saving the extra cost of assignment.

Keep in mind, that data members are always initialized in the order in which they are declared in the class definition, regardless of their order in the initialization list. To avoid strange bugs, which may arise if your data members depend on each other, you should always make sure that the order of the members is the same in the initialization list and the class definition. For the same reason the base class constructor must be the first item in the initialization list. If you omit it altogether, then the default constructor for the base class will be called automatically. In that case, if the base class does not have a default constructor, you will get a compiler error.


If you simply want to pass all constructor arguments to the base-class (=parent), here is a minimal example.

This uses templates to forward every constructor call with 1, 2 or 3 arguments to the parent class std::string.

Code

Live-Version

#include <iostream>
#include <string>

class ChildString: public std::string
{
    public:
        template<typename... Args>
        ChildString(Args... args): std::string(args...)
        {
            std::cout 
                << "\tConstructor call ChildString(nArgs="
                << sizeof...(Args) << "): " << *this
                << std::endl;
        }

};

int main()
{
    std::cout << "Check out:" << std::endl;
    std::cout << "\thttp://www.cplusplus.com/reference/string/string/string/" << std::endl;
    std::cout << "for available string constructors" << std::endl;

    std::cout << std::endl;
    std::cout << "Initialization:" << std::endl;
    ChildString cs1 ("copy (2)");

    char char_arr[] = "from c-string (4)";
    ChildString cs2 (char_arr);

    std::string str = "substring (3)";
    ChildString cs3 (str, 0, str.length());

    std::cout << std::endl;
    std::cout << "Usage:" << std::endl;
    std::cout << "\tcs1: " << cs1 << std::endl;
    std::cout << "\tcs2: " << cs2 << std::endl;
    std::cout << "\tcs3: " << cs3 << std::endl;

    return 0;
}

Output

Check out:
    http://www.cplusplus.com/reference/string/string/string/
for available string constructors

Initialization:
    Constructor call ChildString(nArgs=1): copy (2)
    Constructor call ChildString(nArgs=1): from c-string (4)
    Constructor call ChildString(nArgs=3): substring (3)

Usage:
    cs1: copy (2)
    cs2: from c-string (4)
    cs3: substring (3)

Update: Using Variadic Templates

To generalize to n arguments and simplify

        template <class C>
        ChildString(C arg): std::string(arg)
        {
            std::cout << "\tConstructor call ChildString(C arg): " << *this << std::endl;
        }
        template <class C1, class C2>
        ChildString(C1 arg1, C2 arg2): std::string(arg1, arg2)
        {
            std::cout << "\tConstructor call ChildString(C1 arg1, C2 arg2, C3 arg3): " << *this << std::endl;
        }
        template <class C1, class C2, class C3>
        ChildString(C1 arg1, C2 arg2, C3 arg3): std::string(arg1, arg2, arg3)
        {
            std::cout << "\tConstructor call ChildString(C1 arg1, C2 arg2, C3 arg3): " << *this << std::endl;
        }

to

template<typename... Args>
        ChildString(Args... args): std::string(args...)
        {
            std::cout 
                << "\tConstructor call ChildString(nArgs="
                << sizeof...(Args) << "): " << *this
                << std::endl;
        }

Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to inheritance

How to extend / inherit components? Inheritance with base class constructor with parameters Class is not abstract and does not override abstract method Why not inherit from List<T>? Can an interface extend multiple interfaces in Java? How to call Base Class's __init__ method from the child class? How should I have explained the difference between an Interface and an Abstract class? JavaScript OOP in NodeJS: how? When do I have to use interfaces instead of abstract classes? C++ calling base class constructors

Examples related to constructor

Two constructors Class constructor type in typescript? ReactJS: Warning: setState(...): Cannot update during an existing state transition Inheritance with base class constructor with parameters What is the difference between using constructor vs getInitialState in React / React Native? Getting error: ISO C++ forbids declaration of with no type undefined reference to 'vtable for class' constructor Call asynchronous method in constructor? Purpose of a constructor in Java? __init__() missing 1 required positional argument