views:

250

answers:

3

Hi,

is there a (practicable) way to by-pass the normal (virtual) constructor calling order? (Hard to describe in one sentence, see the)

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 instanciate C, but why does D have to call it when instanciating D?


Thanks in advance for any suggestion.

A: 

On parashift c++-faq-lite this issue is outlined.

Shamster
I believe the author was asking why you always had to call the virtual base classes constructor from the most derived class, and not a particular problem that he was having with the example he gave. The example was just to illistrate his question clearly.
diverscuba23
@diverscuba23: It took me some searching to even understand what the issue was. Now I get it, but don't understand the situation that would lead to this.
Shamster
+3  A: 

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?

Troubadour
> [...] what if class D were to inherit two C's [...]?Hadn't I then to virtually derive from C?
DyP
@DyP: Yes, fair point about two C's. I've edited that out of my answer. The point still stands though of course.
Troubadour
@DyP: Not nessisarily, if C can support having multiple copies of itself in an object, it need not be virtual. Granted its really rare that you would ever want a situation like that, but it is possible to do with the language.
diverscuba23
"It's not an issue of ambiguity [...]", yes, I wanted to say it was nonsense if B called it when you instanciate a C, as C could be derived from a B0 and B1 (look at the diamond). My specific question deals with D, which is a single an non-virtual child to C, and other (non-virtual, single-inheritance) child classes of D. I edit the question.
DyP
+1  A: 

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 vitual 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 vitual base class directly, will not, by the standard, call thier vitual base classes constructor, so it must be called explicitly.

diverscuba23
> Classes that inherit from a vitual base class directly, will not, by the standard, call thier vitual base classes constructor, so it must be called explicitly. That's right for class B, and then, class C could call it. But since C is not the very most derived class, D must call it. Any way to let C call it? D is directly derived from C with single non-virtual inheritance.
DyP
@DyP: Suppose that I latter add a class E that derives from C and then make D multiply derive from both C and E (even if I do not make C virtual) then which C calls the constructor for A?
diverscuba23
@diverscuba23:sry for that, I edited the question. I can assume there is no multiple inheritance of C.
DyP
@DyP: For your specific case it there would be no problems with it, but the language is written for the general case which includes what I have given as an example. The easiest way to ensure that the constructor for a virtual base class is called exactly once for all possible cases is to make it so that the most derived class is responsible for calling it.
diverscuba23
@diverscuba23: I agree and understand (now) why it was designed so. That's why I ask for a workaround of this rule (two-phase init or using inheritance or something)
DyP