Search code examples
c++c++11constructorinitializer-list

C++ delegating ctor and parent ctor with argument


This does not seem to work in C++11:

class B : public A
{
  public:
    B(const A& a)
        : A(a)   // parent constructor for passing the parameter
        , B()    // delegating constructor for init of other members
    {};
  // ...
};

gcc tells me that an initializer for a delegating constructor must appear alone.

How do I both call the constructor of the parent class with the parameter, and call the basic constructor of the B class? (I have a bunch of other constructors in B that need the same behavior).

Right now I am considering writing a private B::init() function and use it in all constructor bodies, but that tastes a bit much of C++03.

What is the preferred solution?


Solution

  • I believe the preferred way of delegation is the other way around, it's not meant to be used to refactor common parts of constructors, but rather to define the simpler one as a special case of a the more complex case.

    So you should start with B(const A& a) and use this as delegation target.

    class B : public A
    {
      public:
        B() : B(A());
        B(const A& a) : A(a)   // parent constructor for passing the parameter
        {};
    };
    

    You are calling A() anyways when creating B.

    The rationale behind it is when you have two "partially specialized" c'tors, you wouldn't be able to use them to initialize the complex one. E.g:

    class B : public A
    {
      public:
        B() {};
        B(int) : B() {};
        B(double) : B() {};
        B(double,int) : B(int), B(double) {}; // can't do it.
    };
    

    I believe the technical reason is explained in Bathsheba's answer. Look what would happen if you had a common part in B():

    class B : public A
    {
      public:
        B() {};
        B(int) : B() {};
        B(double) : B() {};
        B(double,int) : B(int), B(double) {}; //ooops would get B() called twice!
    };
    

    It's the diamond problem known from inheritance. The solution is to reverse the logic.

    class B : public A
    {
      public:
        B() : B(0,0) {};
        B(int a) : B(a,0) {};
        B(double d) : B(0,d) {};
        B(double a, int d) {/*full implementation*/};
    };