Calling a virtual base class's overloaded constructor

随声附和 提交于 2019-12-19 05:44:31

问题


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?


回答1:


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.




回答2:


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?




回答3:


Such are the rules. There are rules for overriding virtual functions and rules for constructing virtual base subobjects. Although both are very similar conceptually, they follow completely different rules, for a reason: overriding a virtual function is explicit. Calling a constructor is implicit for the default constructor.

Virtual functions in virtual base classes are only required to have one final overrider, an overrider that overrides all others overriders. (Virtual functions in non-virtual base classes cannot possibly have two overriders such that one does not override the other.)

But virtual base class constructors are always called from the most derived class, and usually in the implicit form of not bothering to mention the virtual base class in the ctor-init-list, as most classes designed to be used as virtual base classes are "pure interfaces" with no data members and no user initialization.




回答4:


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



来源:https://stackoverflow.com/questions/3495139/calling-a-virtual-base-classs-overloaded-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!