C++多重继承——为什么你不能工作?

8

我正在尝试解决一个有趣的多重继承问题。

祖父类是一个接口类,具有多个方法:

class A
{
public:
    virtual int foo() = 0;
    virtual int bar() = 0;
};

那么还有一些抽象类,部分实现了这个接口。
class B : public A
{
public:
    int foo() { return 0;}
};

class C : public A
{
public:
    int bar() { return 1;}
};

我想使用的类继承自父类,并通过使用指令指定应该从哪里获取方法:

class D : public B, public C
{
public:
    using B::foo;
    using C::bar;
};

当我尝试实例化一个D时,我会因为试图实例化抽象类而出现错误。
int main()
{
    D d; //<-- Error cannot instantiate abstract class.

    int test = d.foo();
    int test2 = d.bar();

    return 0;
}

有人可以帮我理解问题以及如何最好地利用部分实现吗?


2
在菱形继承中,您需要使用虚拟继承。但我不认为仅凭这一点就能解决您的问题。 - David
2个回答

13

你没有使用钻石继承。对于D类的B和C基类,它们各自拥有自己的A基类子对象,因为它们不是通过虚继承从A继承而来的。

因此,在D类中,实际上有四个需要实现的纯虚成员函数:来自B的A::foo和A::bar以及来自C的A::foo和A::bar。

你可能想要使用虚继承。类声明和基类列表应该像这样:

class A
class B : public virtual A
class C : public virtual A
class D : public B, public C

如果您不想使用虚继承,则需要覆盖D中的另外两个纯虚函数:

class D : public B, public C
{
public:
    using B::foo;
    using C::bar;

    int B::bar() { return 0; }
    int C::foo() { return 0; }
};

-2

为了使它们正确继承,您需要将基类设置为virtual。一般规则是,除非您知道自己在做什么并且想要禁用该成员/基类的正常继承,否则所有非私有成员函数和基类都应该是virtual


1
一般规则是所有公共成员函数和基类都应该是虚拟的。什么?这是谁的一般规则?如果有什么的话,关于虚拟成员函数的一般规则是将它们设为私有,并在基类中有一个公共的非虚拟成员函数调用私有的虚拟成员函数(这在GotW文章“Virtuality”中讨论过)。至于虚拟基类……在过去几年中,我只能想到一个需要使用虚拟继承的情况。 - James McNellis
@JamesMcNellis "在过去的几年中,我只能想到一个需要使用虚继承的情况。" 你需要使用虚继承的次数有多少? - curiousguy
@JamesMcNellis:那篇文章基本上是一派胡言。唯一正确的是大多数成员函数(无论是否虚拟)应该是私有的。公共非虚拟成员函数是一场灾难的前兆,基本上意味着该类不能被子类化。 - Chris Dodd
@ChrisDodd 你在说什么啊...伙计,如果你说出你个人的想法,至少不要假装你所说的是事实...gtkmm只是C++类的许多例子之一,其中只有很少的虚函数,通常是受保护的,并且这些类仍然完全可以被子类化(它们非常容易被子类化)。如果你喜欢将所有公共方法都设置为虚函数-那很好。我不喜欢,但我不会告诉你如何编写代码。只是不要把个人习惯当作事实传递给其他人... - cfa45ca55111016ee9269f0a52e771

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