4

在下面的代码中,我收到以下警告和错误:

test.cpp:15: warning: direct base 'B' inaccessible in 'D' due to ambiguity
test.cpp:15: error: no unique final overrider for 'virtual void A::f()' in 'D'

但是,如果我从 A 中删除 B 的虚拟继承(即struct B : public A),我只会收到警告,没有错误。

struct A
{
  virtual void f() = 0;
};

struct B : public virtual A
{
  void f() {}
};

class C : public B
{};

struct D : public C, virtual B
{};

int main()
{
  return 0;
}

为什么?这是可怕的钻石吗?

4

3 回答 3

3

这是因为C以非虚拟方式继承自,BD以虚拟方式继承自B. 这给了你B两次,包括两次f()

B尝试in 的虚拟继承C

B更新:那么,当您从 from中删除虚拟继承时,为什么它会起作用A?因为它改变了“最终覆盖者”。没有 virtual in BfromA和 in CfromB你有A两次:一次 in C(最终覆盖f()in B)和一次 virtual Bin D(最终覆盖f()in B)。如果在Bto中添加虚拟继承AA则只会出现一次,并且将有两个最终覆盖竞争实现纯f()from A,包括 in B、once fromC和 once from virtual B

作为一种解决方法,您可以在usingD 中添加一个,即using C::f;using B::f

见 C++ 10.3/2

于 2013-10-31T17:19:46.640 回答
2

让我们看一下'final overrider'的定义10.3[class.virtual]/2

C::vf类对象的虚成员函数S是最终覆盖器,除非其最派生类S是基类子对象(如果有)声明或继承了另一个覆盖的成员函数vf

在派生类中,如果基类子对象的虚成员函数具有多个最终覆盖器,则程序格式错误。

从 A 的虚继承,只有一个 A 类型的基类子对象,并且它的虚成员函数 f() 有多个 final overrider(每个 B 类型的子对象中都有一个)

如果没有从 A 虚拟继承,则有两个不同的 A 类型的基类子对象,并且它们的虚拟成员函数 f() 每个都有自己的最终覆盖器(每个 B 子对象中都有一个)

于 2013-10-31T17:45:43.377 回答
0

虚拟基础子对象在完整对象中的所有基础子对象之间“共享”。由于 A 在 D::C::B 和 D::B 之间共享,因此无法判断哪个 B 对象应该将其f()称为覆盖A::f().

考虑:

#include <iostream>

struct A {
  virtual void f() = 0;
  virtual ~A() {}
};

struct B : virtual A
{
  void f() { std::cout << "B\n"; }
};

struct C : virtual A
{
  void f() { std::cout << "C\n"; }
};

struct D : C, B {};

int main() {
  D d;
  A *a = dynamic_cast<A*>(&d); // single shared A between B and C
  a->f(); // Should B::f() be called, or C::f()?
}

D 中的 B 和 C 基础子对象都共享相同的 A 基础子对象。当我们调用 A::f() 时,对覆盖函数进行了虚拟查找。但是 B 和 C 都试图覆盖它,那么哪一个“获胜”?x->f()打印“B”还是“C” ?答案是进入这种情况的程序是不正确的。

当我们通过使 B 和 C 非虚拟继承来消除共享时,单独的 A 基子对象各自的功能都被唯一的基类覆盖:

#include <iostream>

struct A {
  virtual void f() = 0;
  virtual ~A() {}
};

struct B : A
{
  void f() { std::cout << "B\n"; }
};

struct C : A
{
  void f() { std::cout << "C\n"; }
};

struct D : C, B {};

int main() {
  D d;
  // two different A objects
  A *a1 = static_cast<A*>(static_cast<B*>(&d));
  A *a2 =  static_cast<A*>(static_cast<C*>(&d));
  a1->f();
  a2->f();
}
于 2013-10-31T17:55:18.267 回答