从抽象基类的多个部分实现继承?

时间:2012-07-26 05:26:10

标签: c++ multiple-inheritance virtual-inheritance

是否可以对抽象接口进行大量部分实现,然后将收集这些部分实现转换为单个具体类通过使用多重继承?

我有以下示例代码:

#include <iostream>

struct Base
{
    virtual void F1() = 0;
    virtual void F2() = 0;
};

struct D1 : Base
{
    void F1() override { std::cout << __func__ << std::endl; }
};

struct D2 : Base
{
    void F2() override { std::cout << __func__ << std::endl; }
};

// collection of the two partial implementations to form the concrete implementation
struct Deriv : D1, D2
{
    using D1::F1; // I added these using clauses when it first didn't compile - they don't help
    using D2::F2;
};

int main()
{
    Deriv d;
    return 0;
}

无法使用以下错误进行编译:

main.cpp: In function ‘int main()’:
main.cpp:27:11: error: cannot declare variable ‘d’ to be of abstract type ‘Deriv’
main.cpp:19:8: note:   because the following virtual functions are pure within ‘Deriv’:
main.cpp:5:18: note:    virtual void Base::F1()
main.cpp:6:18: note:    virtual void Base::F2()

2 个答案:

答案 0 :(得分:10)

Base尝试inheriting virtually

struct D1 : virtual Base
{
    void F1() override { std::cout << __func__ << std::endl; }
};

struct D2 : virtual Base
{
    void F2() override { std::cout << __func__ << std::endl; }
};

如果没有虚拟继承,您的多重继承方案看起来就像是从两个独立且不完整的基类D1D2继承,两者都不能实例化。

答案 1 :(得分:3)

  

是否有可能有一些抽象接口的部分实现,然后通过使用多个继承将这些部分实现收集到一个具体的类中?

每个Base基类子对象带来两个纯虚函数。在Deriv中你想要多少个基础子对象?

  • 如果您想要2个Base基类子对象,Deriv::D1::BaseDeriv::D2::Base(因此从Deriv&Base&的转换将是不明确的)那么您将拥有Deriv中的4个不同虚拟函数:Deriv::D1::Base::F1()Deriv::D1::Base::F2()Deriv::D2::Base::F1()Deriv::D2::Base::F2()。只实现了第一个和最后一个,因此两个中间的是纯虚拟的:Deriv::D1::Base::F2()Deriv::D2::Base::F1()。您有两个完全独立的继承关系:Deriv继承自D1Deriv继承自D2
  • 如果您只想要一个Base基类子对象Deriv::Base,则Deriv中只有2个不同的虚拟函数:Base::F1()Base::F2()

C ++中的非虚拟继承是&#34;具体的&#34;继承,就像包含一样:struct D : B意味着对于每个D对象,只有一个B基类子对象,就像struct C { M m; }意味着对于每个C那样正好是一个M类成员子对象。这些关系是一对一的。

OTOH,虚拟继承更多&#34;抽象&#34;:struct D : virtual B意味着每个D对象都与B基类子对象相关联,但这种关系是多对一的,比如struct C { M &m; }

通常,对于任何派生类D(此处为Deriv),以及B(此处为D)的任何虚拟基础Base,所有虚拟派生自D(此处为BDeriv::D1)的Deriv::D2基类有助于覆盖基类中的虚函数:

  • Base::F1()Deriv::D1::F1()
  • 覆盖
  • Base::F2()Deriv::D2::F2()
  • 覆盖

非虚拟和虚拟继承是非常不同的继承关系,就像非虚拟成员函数和虚函数在派生类和基类中具有相同签名的函数之间引入不同关系一样(隐藏与覆盖)。 p>

与虚拟和非虚拟功能一样,虚拟和非虚拟基类必须在不同的情况下使用(一个不是&#34;比一般的更好&#34;)。

如何修复&#34;你的代码没有虚拟继承?

struct Deriv : D1, D2
{
    using D1::F1; // I added these using clauses when it first didn't compile - they don't help
    using D2::F2;
};

是:使用声明控制名称查找,因此它们会影响可见性和歧义问题,而不会影响虚拟函数覆盖。

使用原始的基于非虚拟继承的设计,为了使Deriv成为具体类,您必须显式实现F1()F2()虚函数签名(有Deriv中的4个虚函数,但只有2个不同的签名),因此您需要2个函数定义:

struct Deriv : D1, D2
{
    void F1() override { D1::F1(); }
    void F2() override { D2::F2(); }
};

请注意,Deriv::F1()会覆盖Deriv::D1::F1()Deriv::D2::F1()