这是有效的C++代码吗?

3

我想知道下面这段代码在C++中是否完全有效:

class A
{
public:
   virtual bool b() = 0;
};

class B
{
public:
   virtual bool b() = 0;
};

class C: public A, public B
{
public:
  virtual bool A::b()
  {
    return true;
  }

  virtual bool B::b()
  {
    return false;
  }
};

使用VS2008编译时没有任何错误,然而在GCC(MinGW)3.4.5上会报错,例如:
cannot declare member function `A::b' within `C'

在实现虚方法的行上。我很好奇这是否只是通常被视为无效的、根据C++标准禁止的代码(在VS中它能够工作,这得益于一些微软非标准化的魔法),还是GCC中的一个错误或不支持的语言特性。

4个回答

17

这是无效的。你不能像那样单独覆盖它们,因为它们将具有相同的签名。

这方面有一篇本周大师的文章。


1
除此之外,非虚拟析构函数就像是一颗定时炸弹。但这不是问题的关键。 :) - wilhelmtell

1

不允许使用限定名称 A::b 作为类 C 的成员名称。


1

由于父类具有相同的函数名称,它不应该编译。此外,您不应该超过一次重载函数b。

如果您参考为此创建的虚拟表:

0(beginning of vtable) - A::b() -> B::b()

你看,由于B类具有与A类相同的函数名称,它会覆盖它,因此现在你有了B::b()来覆盖它(因为它仍然是纯虚函数)。这是由于多重继承。编译器如何区分两者(它们具有相同的签名)?通常,这将失败,因为就像我刚才说的那样,编译器不应该做出决定,它应该告诉你有问题。
在VS上编译可以通过,但你尝试运行它了吗(包括在实际创建文件中)?有时,编译器会懒得对未使用的类弹出错误。

编译器如何区分这两个函数(它们具有相同的签名)?但是,当您拥有具有多个基类的类时,它们本身具有一些共同的父基类(通常需要使用虚继承),也会发生这种情况。当然,如果我们不使用虚继承,编译器无法区分对公共方法的调用,并抛出模棱两可的调用错误,但可以通过将该类实例 dynamic_cast 到我们想要的基类来轻松解决。是的,我在 VS 上以这种方式使用它,而且没有任何问题。 - Martin Zima
@RedDragCZ:就我使用虚拟继承的情况来看,它仅适用于子类从同一基类继承的情况。如果您查看litb链接,所提出的解决方案是使用所谓的辅助类。 - tomzx

0

顺便说一下,只有在尝试使用b方法时,VC才会报错:

C:\temp\test.cpp(33) : error C2668: 'C::b' : ambiguous call to overloaded function
      C:\temp\test.cpp(23): could be 'bool C::b(void)'
      C:\temp\test.cpp(18): or       'bool C::b(void)'
      while trying to match the argument list '(void)'

顺便说一句,Comeau编译器的行为类似,但错误消息更加令人困惑:

"C:\temp\test.cpp", line 33: error: no instance of overloaded function "C::b"
          matches the argument list
            object type is: C
      bool z = c.b();

是的,我知道,如果不解决b()方法应该被调用的问题,它当然无法正常工作,但是在堆上分配C实例并将其向下转换然后调用b()没有问题,例如'dynamic_cast<A*>(c_instance_on_heap)->b()'(这是完全适用的,因为在我的代码中我使用A和B作为接口)。 - Martin Zima
但编译器应该在尝试声明方法时就发出警告,而不是等到访问方法时才发出警告。我不知道为什么编译器会使用这种行为。 - Michael Burr

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