抽象基类的模糊继承:

Posted

技术标签:

【中文标题】抽象基类的模糊继承:【英文标题】:Ambiguous inheritance of abstract base classes: 【发布时间】:2010-11-26 08:57:18 【问题描述】:

我有一个比这复杂得多的类结构,但将问题归结为本质,这描述了我的场景:我有两个类 A 和 B,它们实现了共享共同祖先的纯虚拟基类,并且然后是第三个类 C,它组合了 A 和 B。最后,一个模板类,它填充了纯虚拟基础中的常用方法:

struct I 
  virtual void r()=0;
;

struct A : I ;
struct B : I ;

struct C : A, B 
  void q()
    r();              // the problem is here.
  
;

struct D : C 
  virtual void r()
  
;

C* c = new D;
c->q();

我的问题是,我看不到任何让 C::q 调用 r() 的方法。

void C::q()
  r();    // is ambiguous
  A::r(); // is pure virtual
  B::r(); // also is pure virtual
  D::r(); // C doesn't know about D
  ((D*)this)->r(); // is dubious and requires C to know about D.

如何从 C 中调用 r() 方法以便调用正确的虚拟方法?


抱歉,我应该澄清一下,这里不能使用虚拟继承。我找到了两个解决方案:

struct C : A, B 
  virtual void r()=0;
  ...

struct C : A, B 
   using A::r;
   ...

两者似乎都足以消除对 r() 的调用的歧义,以解决所有问题。

【问题讨论】:

+1 用于解决您的问题并将其分解为最简单的形式。 在没有虚拟继承的情况下,在 C 中 r() 不是会模棱两可吗? 您的意思是虚拟基类还是抽象基类?因为要使I 成为虚拟基地,您需要struct A : virtual I ;struct B : virtual I ; @DumbCoder: r 对编译器来说看起来模棱两可,但事实并非如此。它实现的唯一位置是在 D 中。这就是问题所在。 @Charles:不幸的是,这代表了 COM 继承问题,虚拟基类不能与 COM 混合。 using A::r; 并没有真正的帮助,至少标准说这仍然是模棱两可的。 【参考方案1】:

在 C 中将方法 r 重新声明为纯虚:

struct C : A, B 
  void q()
    r();              // the problem is here.
  

  virtual void r()=0;
;

【讨论】:

不确定为什么这是公认的答案。这是一个黑客。正确答案实际上是从 I 继承的。 通常我会同意。但在我的情况下,我不能使用虚拟继承。在所有非虚拟继承解决方案中,这是最优雅的。【参考方案2】:

尝试虚拟继承

struct A : virtual  I ;
struct B : virtual I ;

【讨论】:

【参考方案3】:

告诉编译器遵循层次结构的哪一部分:

struct C : A, B 
  void q()
    A * p = this;
    p->r();              // recent GCC compiles this
  
;

【讨论】:

【参考方案4】:

这是模棱两可的,因为编译器不知道要调用哪个r(),一个来自A还是来自B。

简单的方法是写:

static_cast<A*>(this)->r();

static_cast<B*>(this)->r();

但我认为这些都不是您要寻找的答案。你通过virtual继承接口我清理情况:

struct A : virtual I ;
struct B : virtual I ;

现在,你可以打电话了

void C::q()  r(); 

如您所愿。对此的简单解释是,通过使用虚拟,C 类只获得接口 I 的一个“副本”,而不是两个。这可以消除您的代码的歧义。

【讨论】:

您不应该使用 dynamic_cast 而不是 static_cast 吗?涉及到虚函数。 不,你是在层次结构上向上,而不是向下。【参考方案5】:

您没有在子结构中重载 r(),所以它仍然是纯虚拟的。即没有实现。

【讨论】:

以上是关于抽象基类的模糊继承:的主要内容,如果未能解决你的问题,请参考以下文章

从抽象基类构造函数创建继承类的实例

从两个抽象类继承,其中一个也需要另一个基类的一部分

详细的解释下类的封装性,抽象性,继承性和多态性。

Typescript派生类和抽象类

抽象类,派生类,继承

面向对象程序设计——抽象基类,访问控制与继承,继承中的类作用域,拷贝函数与拷贝控制