2

当我尝试以通常的方式“解决”通常的钻石问题时出现了奇怪的问题 - 使用虚拟继承:

  A
 / \* both virtual
B   C
 \ /
  D

但是我的基类 A 没有默认构造函数,所以我要从 D 手动调用它。但是,当我尝试将类 E 添加到这个菱形中作为 C 继承时

  A
 / \* both virtual
B   C
 \ / \
  D   E

仍然需要在E构造函数中手动调用A的构造函数,即C不会从E创建A,即使没有多重继承也没有菱形ACE。

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;
  } 

是否可以在不从 E 调用 A 的构造函数的情况下解决此问题?我需要 C 来正确地做到这一点:-)。

或者是否有可能根本不尝试解决钻石问题:

A   A
|   |  no virtual at all
B   C
 \ / \
  D   E

并且仍然尝试用 A 的两个实例声明 D 类的对象,但每次从 D 收集时告诉编译器使用 C 的 A?当我尝试添加

using C::A

进入 D 的声明它仍然会产生明确基数 A 的错误。

4

2 回答 2

3

是否可以在不从 E 调用 A 的构造函数的情况下解决此问题?我需要 C 来正确地做到这一点:-)。

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

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

于 2010-07-18T19:43:01.593 回答
3

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

  • 您可以覆盖派生类中的虚函数;
  • 仅当函数在基类之一中被覆盖而不在其他基类中被覆盖时,您才必须覆盖虚函数;
  • 您不能不覆盖基类构造函数的虚拟基类的初始化列表。

这意味着:

  • 就虚函数覆盖而言,虚继承根本不影响单继承;
  • 但是当涉及到基类构造函数调用时,虚拟继承会影响每个派生类。
于 2011-11-02T22:46:54.387 回答