Modern C++ Features – Inherited and Delegating Constructors

Contents

In my last post I have written about braced-or-equal-initializers for class members, a feature that enables simpler constructors through default values for members. Today’s post is about two related features that can simplify the writing of constructors even further.

Inheriting constructors

Consider a class that derives from a base which needs some parameters to be constructed properly, e.g because you use dependency injection and. That usually means that constructors of the inheriting class need to have the same parameter which is often only passed to the base class:

class Base {
  Dependency* myDependency;
public:
  Base(Dependency* dep) : myDependency(dep) {}
};

class Derived : public Base {
public:
  //constructor does nothing except forwarding to base constructor
  Derived(Dependency* dep) : Base(dep) {}
};

This can get pretty annoying, especially if you have multiple constructors in Base and you want to support them all in the derived class. In C++11 there is a solution to this annoyance: using directives for base class constructors. Instead of writing a complete constructor, you just inherit the base class constructors and are ready to use them:

class Derived : public Base {
  using Base::Base;
};

As you see, I have not used `public` before the using declaration. That is ok, since inheriting constructors are implicitly declared with the same access as the inherited base class constructors.

What about additional members that are not in Base? No sweat, they can be taken care of by brace-or-equal initializers. The compiler will bits and pieces and construct the correct constructor that passes the parameters to the base class constructor and initializes the members with whatever you chose to provide as brace-or-equal initializers.

Whenever you have a constructor that does not contain any logic, and uses its parameters only to forward them to the base class constructor, consider using brace-or-equal initializers for the members and a using directive to inherit the base class constructor.

Delegating Constructors

Imagine a class that has multiple constructors which share a certain part of their logic. If that logic depends on one or more of the constructor arguments you could call a static method, but if that logic has to initialize more than one member variable it becomes difficult to share the logic between the constructors only via static methods.

You’d probably have to duplicate some code in all those constructors, and code duplication is a violation of the DRY principle and therefore neither clean nor simple.

Again, the C++11 standard comes to the rescue with a feature that allows you to call constructors from other constructors, which is called delegating constructors. Let’s have a look at an example, a class that has to acquire two resources to work properly:

class TwinResource {
  ResourceHandle1 firstResource;
  ResourceHandle2 secondResource;

public:
  TwinResource(ResourceSpecifier1 rs1, ResourceSpecifier2 rs2)
    : firstResource(allocResource(rs1)) , secondResource(allocResource(rs2)) {
    if (!firstResource)
      logError(“Resource allocation failed: ” + toString(rs1));
    if (!secondResource)
      logError(“Resource allocation failed: ” + toString(rs2));
    if (!firstResource || !secondResource)
      throw SomeFatalResourceException;
  }
};

This is the most basic constructor. If we want to add some more constrcutors, e.g. constructors that determine the rsources to be allocated by other means we’d have to factor out the resource checking logic to not repeat it all over – but we still would have to call the function in each constructor:

class TwinResource {
  // … members as above…

  void verifyResourcesAreAllocated() {
    // above constructor body goes here
  }

public:
  //the old constructor:
  TwinResource(ResourceSpecifier1 rs1, ResourceSpecifier2 rs2)
    : firstResource(allocResource(rs1)) , secondResource(allocResource(rs2)) {
    verifyResourcesAreAllocated ();
  }
  
  //new constructors:
  TwinResource(ResourceSpecifier1 rs1, double aValue)
    : firstResource(allocResource(rs1)) 
    , secondResource(allocResource(determineResourceSpec2(aValue))) {
    verifyResourcesAreAllocated ();
  }
  
  TwinResource(string aName, ResourceSpecifier rs2)
    : firstResource(allocResource(determineResourceSpec1(aName))) 
    , secondResource(allocResource(rs2)) {
    verifyResourcesAreAllocated ();
  }
};

As you see, the initializations of the resources are in all three constructors, with a lengthy function call sequence, and the call to the verification function has to be repeated as well. Let’s change that with delegating constructors:

  //the old constructor:
  TwinResource(ResourceSpecifier1 rs1, ResourceSpecifier2 rs2)
    : firstResource(allocResource(rs1)) , secondResource(allocResource(rs2)) {
    verifyResourceAreAllocated ();
  }

  //new constructors:
  TwinResource(ResourceSpecifier1 rs1, double aValue)
    : TwinResource(rs1, determineResourceSpec2(aValue)) {}

  TwinResource(string aName, ResourceSpecifier2 rs2)
    : TwinResource(determineResourceSpec1(aName), rs2) {}

Much clearer, isn’t it?

Consider to use delegating constructors to avoid code duplication between constructors.

Constructor delegation can be performed multiple times, i.e. the target constructor can itself be a delegating constructor. However, circular delegations are not allowed.

The bad news for delegating constructors is, that the member initializer list can contain only the call to the target constructor, i.e. no further member initialization is allowed except for the braced-or-equal-initializers which are applied in the principal constructor, which is the last target constructor in a chain of delegations that itself is not a delegating constructor.

Conclusion

Inheriting constructors and delegating constructors can, together with braced-or-equal-initializers, considerably simplify the writing of class constructors. As always, don’t overuse those features, e.g. avoid long chains of constructor delegation, since a reader preferably should still be able to understand what is going on without effort.

Previous Post
Next Post

4 Comments


    1. Hi Clare, thanks for your interest and the hint about the missing tag.

      I am aware that not all compilers support all details of the newer standards. I myself have to put up with a compiler that does not support much of C++11 except static_assert and (seemingly incomplete) r-value references. I test the examples mostly with Clang, because that is the most advanced compiler I know of when it comes to implementation of newer standard features. I’ll have to leave it to the reader to check if a given feature works with a particular other compiler.

      Reply

  1. Should’n this comma be deleted in all examples: “ResourceSpecifier2, rs2)”?

    Reply

    1. Thanks, I fixed that and a few other hickups.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *