虚拟继承:错误:没有唯一的最终重写器

问题描述 投票:0回答:3

我知道在提出这个问题之前,这里已经介绍了虚拟继承,在提出这个问题之前,我详细介绍了虚拟继承,并详细介绍了类似问题的详细信息,如下所示:

多重钻石继承编译无需虚拟但不使用为什么 GCC 给我一个错误 - 最终重写器

我的问题略有不同,因为我没有使用纯虚函数,而是显式使用虚拟继承来拥有一个唯一的

base
类。层次结构如下:

   base
    /\
   /  \
 der1 der2
   \  /
   der3

我知道派生问题上的可怕钻石,这就是我使用虚拟继承的原因。

#include <iostream>
class base
{
public :

    base()
    {
        std::cout<<"base()" << std::endl;
    }
    virtual void fun()
    {
        std::cout<<"base" << std::endl;
    }
};

class der1: virtual public base
{
public :
    void fun()
    {
        std::cout<<"der1" << std::endl;
    }
};

class der2 : virtual public base
{
public :
    void fun()
    {
        std::cout<<"der2" << std::endl;
    }
};

class der3 : public der1,public der2
{
    public :
    /*void fun()
    {
        std::cout<<"der3" << std::endl;
    }*/
    //if I took out the comment and the function 
    //is defined it compiles fine as expected
};

int main()
{
    base *p=new der3;
    //used scope operation explicitly to avoid ambiguity
    p->base::fun(); //here it complains about 'no unique final overrider for fun'
    return 0;
}

我的理解是,由于我使用的是虚拟继承,因此应该只有一个

base,
实例,并且使用作用域运算符,我可以毫不含糊地调用虚拟
fun
函数。该函数不是纯虚函数。如果我确实在
der3
类上留下实现,则会出现编译器错误:

错误:‘der3’中的‘virtual void base::fun()’没有唯一的最终覆盖

我可以看到这个问题是如何工作的(最终覆盖者)。但我的没有。

base::fun
der1::fun
der2::fun
之间是否混淆了?作用域运算符有什么帮助吗?

任何线索或帮助表示赞赏。我正在使用 g++ 4.6.3。

c++ overriding multiple-inheritance virtual-functions virtual-inheritance
3个回答
15
投票

最派生的类必须提供虚拟基类中虚拟函数的实现 - 否则它如何提供基类接口,因为中间类(即您的

der1
der2
)已经提供了两种替代方案- 它应该调用哪一个?您必须消除这种情况的歧义(即使用
der3::fun()
)。

当然,您实际上并没有调用

der3::fun()
,因为您明确请求
base::fun()
,但这并不意味着规则不适用,就像认为如果不尝试就可以实例化抽象类一样调用纯虚函数......在代码解决这些松散的问题之前,程序的格式是错误的。


10
投票

使用作用域解析运算符指定要调用

base::fun
不会使错误消失,因为即使
main()
为空,程序也会出现格式错误。您根本不允许出现这样一种情况:虚拟函数在程序中存在的任何派生类中具有多个最终重写器。

非正式地说,仅仅因为尝试调用

p->fun()
would 是不明确的,即使你不这样做,程序也是不正确的。

注意:这与重载函数的情况形成鲜明对比,在重载函数中,潜在的歧义是允许的——甚至可能是不可避免的——只要你避免调用实际上是歧义的。为什么规则不同?基本上,这是因为即使构造一个

der3
类型的对象也无法以合理的方式完成——vtable 应该指向哪个版本的
fun


0
投票

因为你有虚拟继承,

der3
类型的对象只会继承
base
的一个实例,也就是说,它不会像没有虚拟继承那样拥有两个
base
的副本。这意味着
der3
只能有一种
fun()
方法。如果
fun()
方法不是虚拟的,那么您将拥有该方法的副本。

由于在您的情况下只能有一种

fun()
方法,因此继承两个版本会导致歧义。您要么必须删除
der1
der2
覆盖
fun()
之一,才能解决歧义(然后
der3
将继承剩下的那个),或者您必须提供
der3
'自己的版本。

© www.soinside.com 2019 - 2024. All rights reserved.