是否可以对抽象接口进行大量部分实现,然后将收集这些部分实现转换为单个具体类通过使用多重继承?
我有以下示例代码:
#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()
答案 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; }
};
如果没有虚拟继承,您的多重继承方案看起来就像是从两个独立且不完整的基类D1
和D2
继承,两者都不能实例化。
答案 1 :(得分:3)
是否有可能有一些抽象接口的部分实现,然后通过使用多个继承将这些部分实现收集到一个具体的类中?
是
每个Base
基类子对象带来两个纯虚函数。在Deriv
中你想要多少个基础子对象?
Base
基类子对象,Deriv::D1::Base
和Deriv::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
继承自D1
而Deriv
继承自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
(此处为B
,Deriv::D1
)的Deriv::D2
基类有助于覆盖基类中的虚函数:
Base::F1()
被Deriv::D1::F1()
Base::F2()
被Deriv::D2::F2()
非虚拟和虚拟继承是非常不同的继承关系,就像非虚拟成员函数和虚函数在派生类和基类中具有相同签名的函数之间引入不同关系一样(隐藏与覆盖)。 p>
与虚拟和非虚拟功能一样,虚拟和非虚拟基类必须在不同的情况下使用(一个不是&#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()
。