让我们想象以下情况: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
。由于使用A::f
对象无法访问C
,因此请求实现它是否有意义?
答案 0 :(得分:1)
C
也继承自B
,在考虑从A
继承的函数时没有什么区别。因此,当编译器发现C
没有从A
覆盖纯虚拟时,它会使它成为一个抽象类。
答案 1 :(得分:1)
源自A的抽象要求是子类实现虚函数
不完全。要求是子类使用非纯函数覆盖纯虚函数。一个基类中的函数不会覆盖另一个基类中的函数; C
本身必须声明覆盖是非抽象的。
但这是必要的吗?
是。您必须覆盖从A
派生的类中的函数;在这种情况下,这意味着C
。
C
继承A
和B
的顺序是否相关?
不,声明顺序没什么区别。必须在从A
派生的类中声明覆盖。
但在这种情况下(如果我错了,请更正我),
C::f
如果已实施,则会覆盖B::f
,而不是A::f
。
无论基类的声明顺序如何,它都会覆盖两者。
由于使用
A::f
对象无法访问C
,因此请求实现它是否有意义?
两者仍然可以访问(虽然名称需要合格,因为不合格的f
是不明确的)。仍然需要重写纯函数以使派生类非抽象。
答案 2 :(得分:0)
由于其他答案尚未针对您的新问题进行更新,因此以下是答案。
但在这种情况下(如果我错了,纠正我),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
。