C++ 菱形子问题:分支中的非多重继承仍然需要类构造函数

C++ 菱形子问题:分支中的非多重继承仍然需要类构造函数,c++,inheritance,multiple-inheritance,diamond-problem,C++,Inheritance,Multiple Inheritance,Diamond Problem,当我试图用通常的方法“解决”常见的菱形问题时,出现了一个奇怪的问题-使用虚拟继承: A / \* both virtual B C \ / D 然而,我的基类A没有默认构造函数,所以我从D手动调用它。然而,当我尝试将类E作为C继承添加到这个菱形中时 A / \* both virtual B C \ / \ D E 仍然需要手动调用E中构造函数的构造函数,即C不知道从E创建什么,即使没有多重继承或菱形A-C-E class A

当我试图用通常的方法“解决”常见的菱形问题时,出现了一个奇怪的问题-使用虚拟继承:

  A
 / \* both virtual
B   C
 \ /
  D
然而,我的基类A没有默认构造函数,所以我从D手动调用它。然而,当我尝试将类E作为C继承添加到这个菱形中时

  A
 / \* both virtual
B   C
 \ / \
  D   E
仍然需要手动调用E中构造函数的构造函数,即C不知道从E创建什么,即使没有多重继承或菱形A-C-E

class A                     
   {public: 
      A (int _N): N(_N) {};
      void show()
        {cout<<"A"<<N;} 
    protected:
      int N;
   }; 
class B: public virtual A   
   { public: 
       B(int n): A(2*n) {};
       void show()
        { cout<<"B"<<N;} 
   }; 
class C: public virtual A   
   { public: 
       C(int n): A(3*n) {};
       void show()
        { cout<<"C"<<N;} 
   }; 
class D: public B,C 
   { public: 
       D(): B(1), C(2), A(3) {};
       void show()
        { cout<<"D"<<N;} 
   }; 

class E: public virtual C
   { public:
       E(): C(1) {};
       void show()
        { cout<<"E"<<N;} 
   }; 

int main()
  {D d;       // OK
   A *a = &d; 
   a->show(); 

   E e;        // NOT OK, no function A::A() to call in E::E()
   A *a2 = &e;
   a2->show();
   return 0;
  } 
并且仍然尝试用两个A实例声明类D的对象,但每次从D冷却时都告诉编译器使用C的A?当我尝试添加

using C::A
在D的声明中,它仍然会产生明确的基数A的错误

是否可以在不从E调用构造函数的情况下解决此问题?我需要C来正确地完成它:-)

最派生类的构造函数(在本例中为
E
)负责调用任何虚拟基类的构造函数


C
的构造函数不能调用
A
的构造函数,因为
C
不是最派生的类。虚拟基类是在任何直接基类之前初始化的,因此
E
必须通过
A
初始化才能初始化
C

是的,虚拟基类构造函数调用与虚拟函数重写不同:

  • 可以重写派生类中的虚拟函数
  • 只有当虚函数在一个基类中被重写,而不是在其他基类中被重写时,才必须重写虚函数
  • 不能重写基类构造函数的虚拟基类的init列表
这意味着:

  • 就虚函数重写而言,虚继承根本不影响单个继承
  • 但当涉及到基类构造函数调用时,虚拟继承会影响每个派生类

谢谢,这是可以理解的,那么这就是虚拟继承的确切含义吗?现在我明白了。这里可能不需要虚拟继承,但不幸的是,它不会很舒服(因为有很多来自E的派生,每个派生都应该以与C相同的方式调用构造函数,等等)。也许有一种方法可以在没有虚拟继承的情况下绕过钻石问题(以类似于使用的方式)?@尼克:用这样一个抽象的例子很难说。老实说,我通常在编写的代码中避免复杂的继承层次结构。对于一般情况,其他人可能会有一个好的、实用的解决方案。我在想。。。在我的特殊情况下,我不需要C是A的孩子。E可以是A(与C一起)的直接子代@詹姆斯,再次非常感谢。
using C::A