是有可能有许多的抽象接口的部分实现的,然后通过使用多个传承收集这些部分实现成一个单一的具体类 ?
我有下面的代码示例:
#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()
尝试几乎继承自Base
:
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
,两个国家都不能被实例化。
是有可能有许多的抽象接口的部分实现的,然后通过使用多个传承收集这些部分实现成一个单一的具体类?
是。
每个Base
基类子对象带来了两个纯虚函数。 如何将这些基地的子对象的很多,你在想Deriv
?
- 如果你想2
Base
的基类的子对象, Deriv::D1::Base
和Deriv::D2::Base
(因此转换从Deriv&
到Base&
将是不明确的),那么你将有4个不同的虚拟功能在Deriv
: 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
,那么你将有只有2个不同的虚拟功能Deriv
: Base::F1()
Base::F2()
在C ++中的非虚拟继承是“混凝土”继承,像遏制: struct D : B
意味着对于每个D
对象恰好有一个B
基类子对象,就像struct C { M m; }
struct C { M m; }
意味着对于每个C
恰好有一个M
类成员子对象。 这些关系是一个对一个。
OTOH,虚拟继承是一个比较“抽象”: struct D : virtual B
意味着对于每个D
对象与相关联的B
基类子对象,但这种关系是多到一个,如struct C { M &m; }
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()
非虚拟和虚拟继承是非常不同的继承关系,就像如果非虚拟成员函数和一个虚函数中引入功能之间不同的关系具有相同签名的派生和基类(隐藏与首要)。
像虚拟和非虚函数,虚拟和非虚拟基类必须在不同的情况下使用(有一个没有通常比其他的“更好”)。
如何“修理”你的代码,而虚拟继承?
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()
虚函数签名(有4个虚函数Deriv
,但只有2个不同签名),所以你需要2下函数的定义:
struct Deriv : D1, D2
{
void F1() override { D1::F1(); }
void F2() override { D2::F2(); }
};
需要注意的是Deriv::F1()
覆盖Deriv::D1::F1()
和Deriv::D2::F1()