Inheriting Constructors

In C++, derived classes cannot inherit the constructors of their base classes -- nor can they inherit assignment operators.

In most cases, this makes sense. In others, it is a silly and painful restriction. Luckily templates can be used to overcome this restriction in all cases where such inheritence can be unabiguously defined.

Why inheriting constructors does NOT make sense

Derived classes typically add additional data members to the base class. These members are likely to require their own initialization logic -- so how can inheriting constructors from a base class really work? For example:

    class BaseClass
    {
    public:
	int x_;

	BaseClass(int x)
	: x_(x)
	{
	}
    };

    class DerivedClass
    {
    public:
	string y_;
	DerivedClass(string const &y)
	: BaseClass(47),
	  y_(y)
	{
	}
    };

In this case, the derived class' constructor sets a specific value for the constructor parameter to the base class -- but what if the DerivedClass were designed to take an integer parameter? What would the parameter order be: Would it be "y,x", or "x,y"?

And what if the derived class were to use multiple inheritence? What order of parameters would make sense for the DerivedClass' constructor?

When inheriting constructors does makes sense

Despite the general ambiguity of inheriting constructors, there are many specific cases when it does makes sense. Wrapping a base class with trivial derived class functionality is a common enough practice that a solution to inheriting constructors is worth commenting on.

When wrapping a class, one does not want to be saddled with a never ending series of trivial maintenance changes to deal with the editing of the wrapped class. Without some solution to the inheriting constructors problem, any change to a base class's constructors would necessarily require a change to the derived class -- even though the sole purpose of the derived class is to mimic the base class.

Member template constructors

The solution to this maintenance problem is the use of template member constructors. Don't fear templates! Kept to a minimum, templates add a lot of value with little risk. This is one of the simplest uses of templates that can be imagined. Here's a simple example of the derived class:

    class DerivedClass
    : public BaseClass
    {
    public:

	DerivedClass() {} // assumes the base class requires
			  // no constructor parameters

	template<class T>
	  DerivedClass(T t)
	  : BaseClass(t)
	  {
	      // If this function fails to compile then the
	      // calling code is not passing the right number
	      // of parameters
	  }

	template<class T, class U>
	  DerivedClass(T t, U u)
	  : BaseClass(t, u)
	  {
	      // If this function fails to compile then the
	      // calling code is not passing the right number
	      // of parameters
	  }

	  ...


    };

  
As can be seen from the above example, the template constructors for the derived class are set up to accept any imaginable parameter type and give said parameters to the derived class. This of course defers error detection to the derived class, but at least we let good code compile properly.

Of course, this same strategy can be employed even if there are additional DerivedClass specific constructor parameters. For example:


    class DerivedClass
    : public BaseClass
    {
    public:

	int m_;

	DerivedClass(int m) 
	: m_(m)
	{
	}

	template<class T>
	  DerivedClass(int m, T t)
	  : BaseClass(t),
	    m_(m)
	  {
	      // If this function fails to compile then the
	      // calling code is not passing the right number
	      // of parameters
	  }

	template<class T, class U>
	  DerivedClass(int m, T t, U u)
	  : BaseClass(t, u),
	    m_(m)
	  {
	      // If this function fails to compile then the
	      // calling code is not passing the right number
	      // of parameters
	  }

	  ...

    };
  
Here, the derived class specific constructor parameters are assumed to always be first in the list -- but the code could have been written to place them at the end.