Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a virtual base class's overloaded constructor

Is there a (practical) way to by-pass the normal (virtual) constructor calling order?

Example:

class A
{
    const int i;

public:
    A()
      : i(0)
    { cout << "calling A()" << endl; }

    A(int p)
      : i(p)
    { cout << "calling A(int)" << endl; }
};

class B
    : public virtual A
{
public:
    B(int i)
      : A(i)
    { cout << "calling B(int)" << endl; }
};

class C
    : public B
{
public:
    C(int i)
      : A(i), B(i)
    { cout << "calling C(int)" << endl; }
};

class D
    : public C
{
public:
    D(int i)
      : /*A(i), */ C(i)
    { cout << "calling D(int)" << endl; }
};


int main()
{
    D d(42);
    return 0;
}

Output:

calling A()
calling B(int)
calling C(int)
calling D(int)

What I want to have is something like:

calling A(int)
calling B(int)
calling C(int)
calling D(int)


As you see, there is virtual inheritance involved, which leads the constructor of D to call the constructor of A first, but since no parameter is provided, it calls A(). There's the const int i that needs initialisation, so I've got a problem.

What I'd like to do is to hide the inheritance details of C, that's why I'm looking for a way to avoid calling A(i) in D's (and every derived) constructor's initialisation list. [edit] In this specific case, I can assume there are only non-virtual single-inheritance child classes of C (as D is one). [/edit]

[edit]

Virtual base classes are initialized before any non-virtual base classes are initialized, so only the most derived class can initialize virtual base classes. – James McNellis

That's exactly the point, I don't want the most derived class to call the virtual base class constructor. [/edit]

Consider the following situation (not represented in the code example above):

  A
 / \
B0  B1
 \ /
  C
  |
  D  

I understand why C has to call the ctor of A (ambiguity) when you instantiate C, but why does D have to call it when instantiating D?

like image 829
dyp Avatar asked Aug 16 '10 16:08

dyp


2 Answers

Unfortunately, you will always have to call the virtual base classes constructor from the most derived class.

This is because you are saying that the virtual base is shared between all classes that derive from it for the instance of the object. Since a constructor may only be called once for a given instaniation of an object, you have to explicitly call the constructor in the most derived class because the compiler doesn't know how many classes share the virtual base (paraphrased (probably poorly) from The C++ Programming Language 3rd edition, section 15.2.4.1). This is because the compiler will start from the most base class's constructor and work to the most derived class. Classes that inherit from a virtual base class directly, will not, by the standard, call their virtual base classes constructor, so it must be called explicitly.

like image 131
diverscuba23 Avatar answered Sep 20 '22 03:09

diverscuba23


I understand why C has to call the ctor of A (ambiguity) when you instanciate C, but why does D have to call it when instanciating D?

For the same reason that C has to call it. It's not an issue of ambiguity, it's the fact that A's constructior must be called only once (since it's a virtual base).

If you were hoping that C might be able to initialise A's constructor then what if class D were to inherit C and another class that ultimately inherits A?

like image 33
Troubadour Avatar answered Sep 21 '22 03:09

Troubadour