抽象基类的模糊继承:

11

我有一个比这个更加复杂的类结构,但是将问题简化到其本质,可以描述我的情况:我有两个类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();

我的问题是,我看不到任何调用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()的歧义,以便一切都能解决。


6
感谢您将问题简化到了最简单的形式,给你点赞。 - Ólafur Waage
在C++中,如果没有使用虚继承,r()不会产生歧义吗? - DumbCoder
你是指虚基类还是抽象基类?因为要将 I 设为虚基类,你需要这样写:struct A : virtual I {};struct B : virtual I {}; - CB Bailey
@DumbCoder:r在编译器中看起来很模糊,但实际上并不是。它唯一的实现位置就在D语言中。这就是问题所在。 @Charles:不幸的是,这代表了一个COM继承问题,虚基类不能与COM混合使用。 - Chris Becke
using A::r; 并不能真正解决问题,至少标准规定这仍然是模棱两可的。 - Johannes Schaub - litb
5个回答

4

在C++中重新声明方法r为纯虚函数:

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

  virtual void r()=0;
};

1
不确定为什么这个答案被接受了。这是一个hack。正确的答案是从I进行虚拟继承。 - T33C
通常我会同意。但在我的情况下,我不能使用虚拟继承。在所有非虚拟继承的解决方案中,这是最优雅的。 - Chris Becke

3

尝试使用虚继承

struct A : virtual  I {};
struct B : virtual I {};

2

告诉编译器要跟随哪个层次结构:

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

2

这是有歧义的,因为编译器不知道该调用哪个r()函数,A中的还是B中的。

简单的方法是写成:

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

或者

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

但我认为这并不是你想要的答案。你可以通过继承接口I并使用virtual来清理这种情况:

struct A : virtual I {};
struct B : virtual I {};

现在,您可以调用。
void C::q() { r(); }

正如你所期望的那样。简单来说,通过使用虚拟的方式,类C只得到了接口I的一个“副本”,而不是两个。这样可以消除代码的歧义。


你应该使用 dynamic_cast 而不是 static_cast,因为涉及到虚函数。 - DumbCoder
不,你正在向上层级移动,而不是向下。 - Simone

-1
你在子结构体中没有重载 r(),所以它仍然是纯虚函数,即没有实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接