继承的纯虚函数
Posted
技术标签:
【中文标题】继承的纯虚函数【英文标题】:Inherited pure virtual functions 【发布时间】:2015-01-15 14:19:46 【问题描述】:让我们想象以下情况:A
是一个抽象类,定义了一个纯虚函数void f()
; B
是一个实现函数void f()
的类; C
继承自 A
和 B
:
struct A
void virtual f() =0;
;
struct B
virtual void f()
;
struct C : public A, public B
;
问题可能是:C
是抽象类吗?源自A
抽象的要求是子类实现了虚函数void f()
。 C
没有直接实现,而是继承自B
。
我已经可以回答这个问题了:是的,C
是一个抽象类。如果你试图实例化一个C
类型的对象,你会得到一个编译错误。所以实际的问题是:为什么C
是一个抽象类?
我认为A::f
和B::f
具有相同的名称和签名这一事实不足以在这些函数之间建立对应关系,因此可以说B::f
实现了A::f
。从技术角度来看,我可以看到这些函数“驻留在”C
类型对象的不同部分(尽管我不确定我的理解是否完整)。但是从概念的角度来看,我可以很容易地想象一个类C
想要成为抽象类A
的实现,并且为了实现纯虚函数f
,它使用了它的父类之一。解决办法大概是这样:
struct C : public A, public B
virtual void f() B::f();
;
,这在我的实验中有效。但是这个技巧有必要吗?
编辑:
进一步的问题:C
从A
和B
继承的顺序是否相关?如果我写以下内容会改变什么吗?
struct C : public B, public A
;
答案(再次,我测试我的代码,然后我尝试问一些重要的问题)是否定的,它不会改变任何东西。但在这种情况下(如果我错了,请纠正我),C::f
,如果实施,将覆盖B::f
,而不是A::f
。由于使用C
对象无法访问A::f
,因此请求实现它是否有意义?
【问题讨论】:
去掉“trick”并查看C instance;
是否编译,看看是否有必要。
我尝试了使用和不使用“技巧”。这是必要的,否则C
被认为是抽象的。 “诀窍”是使用B::f
作为所需虚函数的实现。事实上,您所需要的只是实现它。
【参考方案1】:
C
也继承自 B
在考虑从 A
继承的函数时并没有什么区别。因此,当它的编译器看到 C
没有覆盖来自 A
的纯虚拟时,它会使其成为一个抽象类。
【讨论】:
【参考方案2】:A是抽象派生出来的要求是子类实现虚函数
不完全是。要求是子类覆盖纯虚函数,具有非纯函数。一个基类中的函数不会覆盖另一个基类中的函数; C
本身必须将覆盖声明为非抽象的。
但是这个技巧有必要吗?
是的。您必须覆盖派生自A
的类中的函数;在这种情况下,这意味着C
。
C
从A
和B
继承的顺序是否相关?
不,申报顺序几乎没有区别。必须在派生自 A
的类中声明覆盖。
但在这种情况下(如果我错了,请纠正我),
C::f
,如果实施,将覆盖B::f
,而不是A::f
。
无论基类的声明顺序如何,它都会覆盖两者。
由于无法使用
C
对象访问A::f
,因此请求实现它是否有意义?
两者仍然可以访问(尽管名称需要限定,因为不限定的f
是不明确的)。仍然需要重写纯函数以使派生类成为非抽象类。
【讨论】:
【参考方案3】:由于尚未针对您的新问题更新其他答案,以下是它们的答案。
但在这种情况下(如果我错了,请纠正我),如果实施,C::f 将覆盖 B::f,而不是 A::f。
你错了一半。无论继承顺序如何,A::f
和 B::f
都会被 C::f
覆盖。
由于使用 C 对象无法访问 A::f,因此请求实现它是否有意义?
但A::f
可以使用C
对象访问。考虑一下这个非常典型的继承用法:
void call_f(A& a)
a.f();
int main()
C c;
call_f(c);
如果C
没有覆盖A::f
,那么这不可能工作。 A
的具体子类必须实现 A::f
是有道理的。
【讨论】:
以上是关于继承的纯虚函数的主要内容,如果未能解决你的问题,请参考以下文章