从抽象基类的多个分部实现继承
Inherit from multiple partial implementations of an abstract base class?
是否可以拥有抽象接口的多个部分实现,然后使用多重继承将这些部分实现收集到单个具体类中?
我有以下示例代码:
#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&
的转换是模棱两可的(,那么你将在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++中的非虚拟继承是"具体的"继承,如包含:struct D : B
意味着对于每个D
对象,只有一个B
基类子对象,就像struct C { M m; }
意味着对于每个C
,只有一个M
类成员子对象。这些关系是一对一的。
OTOH,虚拟继承是一个更"抽象"的:struct D : virtual B
意味着对于每个D
对象都与一个B
基类子对象相关联,但这种关系是多对一的,就像struct C { M &m; }
一样。
一般来说,对于任何派生类D
(此处Deriv
(,以及D
的任何虚拟基B
(此处Base
(,所有虚拟派生自B
D
的基类(此处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()
虚函数签名(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()
。
- 我应该避免多重实现继承吗
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 类继承,ENUM 与 AST 类实现的问题
- C++ 使用接口和默认实现继承
- C++ 多重继承:使用基类 A 的实现实现基类 B 的抽象方法
- 将实现从继承的 CRTP 注入到继承的接口类
- 接口实现和私有继承之间的交互
- C 如何仅实现多个继承类的一个构造函数
- 如何在部分类模板专业化中实现继承
- 从接口和实现C 继承
- 编译器如何实现继承
- 为什么无法使用'using'指令实现继承的纯虚拟方法?
- 在子类中实现继承类的方法(param=指向父级的指针)(param=指向子级的指针)
- 从抽象基类的多个分部实现继承
- C++通过继承函数实现继承的抽象函数
- 如何在C++实现继承并解决错误"parent class is not accessible base of child class"?
- 编译器如何实现C++继承
- 代理dll:方法覆盖/方法转发(COM实现继承)
- 类型a必须实现继承的纯虚拟方法b
- 如何实现继承表单fstream的类