Inherited constructors in C++11

In C++, a function in a derived class with the same name as one (or a set of overloads) in a base class, hides the function (or the overloads) from the base class. Here is an example:

struct base 
{
   void foo() {std::cout << "base::foo" << endl;}
   void foo(int a) {std::cout << "base::foo(" << a << ")" << endl;}
   void foo(int a, double b) {std::cout << "base::foo(" << a << "," << b << ")" << endl;}
};

struct derived : base
{
   void foo(double a) {std::cout << "derived::foo(" << a << ")" << endl;}
};

int main()
{
   derived d;

   d.foo();          // error: derived::foo does not take 0 arguments
   d.foo(42);
   d.foo(42, 3.14);  // error: derived::foo does not take 2 arguments

   return 0;
}

As the comments show, calls to foo() and foo(42, 3.14) trigger compiler errors. The call to foo(42) is all right because there is an implicit conversion from int to double.

It is possible to “un-hide” the functions from the base class with a using directive.

struct derived : base
{
   void foo(double a) {std::cout << "derived::foo(" << a << ")" << endl;}
   using base::foo;
};

The code in main will now compile and the program will output:

base::foo
base::foo(42)
base::foo(42,3.14)

A limitation of this feature was that it didn’t work with constructors. In other words the following is failing to compile.

struct base 
{
   base() {std::cout << "base()" << endl;}
   base(int a) {std::cout << "base(" << a << ")" << endl;}
   base(int a, double b) {std::cout << "base(" << a << "," << b << ")" << endl;}
};

struct derived : base
{
   using base::base;
};

int main()
{
   derived d1;
   derived d2(42);
   derived d3(42, 3.14);

   return 0;
}

This can be achieved by writing a matching constructor in the derived for every constructor in base.

struct derived : base
{
   derived():base() {}
   derived(int a):base(a) {}
   derived(int a, double b):base(a, b) {}
};

However, when you have hierarchies with many derives and you have to provide one or more constructors like this just to call the right constructor of base it becomes annoying.

A solution to the problem is provided by C++ 11. The using directive now works also for constructors. The derived class in the last example is semantically equivalent to

struct derived : base
{
   using base::base;
};

This code will produce the following output:

int main()
{
   derived d1;
   derived d2(42);
   derived d3(42, 3.14);

   return 0;
}
base()
base(42)
base(42,3.14)

Keep in mind that the lifted constructors are simply calling the base constructors and do not perform any member initialization. Suppose you had some member like in the following example:

struct derived : base
{
   using base::base;

   int value;
};

Regardless what constructor is used to create the object, value will remain uninitialized. To avoid that you have two options:

  • don't use the using directive to lift the constructors from base and write the constructors for the derived class explicitly
  • initialize the member variables explicitly (using non-static data member initializers):
    struct derived : base
    {
       using base::base;
    
       int value {0};
    };
    

Availability. At the time of writing this post, inherited constructors are supported by g++ 4.8 and clang 3.3. Visual Studio does not support it and is not known in which version in the future it will. Non-static data member initializers are supported by Visual Studio 2013 RTM, g++ 4.7 and clang 3.0.

1 thought on “Inherited constructors in C++11”

  1. Just one thing that I found a little puzzling (I’m just learning C++, though). If in the derived class you add a new specific constructor after you use the using directive, you lost the possibility of using the default constructor (even though it is in the base class). So, if it is needed a specific constructor, you need to add a default one, even one using that no-parameter base constructor:

    struct derived : base
    {
    using base::base; //inheriting the constructors of the base class
    derived(int a, string b) {std::cout << "derived(" << a << ", " << b << ")" << std::endl;} //a new constructor
    derived() : base() {} //needed after the constructor before
    };

    with this, the code just works again.

    Reply

Leave a Comment