简体   繁体   中英

Diamond Problem C++: Derived class of diamond calls default constructor

So as part of the public API of my program I expose class D, such that the user inherits from class D to create their own classes.

However class D is the tip of the deadly diamond and I have run into an issue where the user's classes are calling the default constructor of class A, instead of the parametrized constructor as desired.

  A
 / \
B   C
 \ /
  D
  |
E or F

In the following code, class E is a clean API however calls the wrong A constructor. Class F works as intended, however the user has to add A's parameterised constructor, which is ugly because that class is an internal class.

Is there a way to have class E work as intended? Why is this happening?

#include<iostream>
using namespace std;
class A {
public:
    A(int x)  { cout << "A::A(int ) called" << endl;   }
    A()     { cout << "A::A() called" << endl;   }
};
  
class B : virtual public A {
public:
    B(int x): A(x)   {
       cout<<"B::B(int ) called"<< endl;
    }
};
  
class C : virtual public A {
public:
    C(int x): A(x) {
        cout<<"C::C(int ) called"<< endl;
    }
};
  
class D : public B, public C  {
public:
    D(int x): A(x), B(x), C(x)   {
        cout<<"D::D(int ) called"<< endl;
    }
};

class E : public D {
public:
    E(int x): D(x) {
        cout<<"E::E(int ) called"<<endl;
    }
};

class F : public D {
public:
    F(int x): D(x), A(x) {
        cout<<"F::F(int ) called"<<endl;
    }
};
  
int main()  {
    D d(0);
    cout<<endl;
    E e(1);
    cout<<endl;
    F f(2);
}

Output:

A::A(int ) called
B::B(int ) called
C::C(int ) called
D::D(int ) called

A::A() called
B::B(int ) called
C::C(int ) called
D::D(int ) called
E::E(int ) called

A::A(int ) called
B::B(int ) called
C::C(int ) called
D::D(int ) called
F::F(int ) called

When constructing a class that has any virtual bases, initializers that name a virtual base class are only called for the most derived class. If your class has any virtual base classes, and you want to use the non-default constructor of that virtual base, then you must specify that constructor in the derived class.

1 " All virtual base subobjects are initialized before any non-virtual base subobject, so only the most derived class calls the constructors of the virtual bases in its member initializer list: ... "

2 " The initializers where class-or-identifier names a virtual base class are ignored during construction of any class that is not the most derived class of the object that's being constructed. "

This topic is relatively new to me, so I hope anybody with more experience will point out any nuance I missed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM