考虑示例:
#include <iostream>
class A {
public:
virtual void f();
};
void A::f()
{
std::cout << "f() from A\n";
}
class B: public A {
public:
virtual void f() = 0;
};
class C: public B {
public:
void f();
};
void C::f()
{
std::cout << "f() from C\n";
}
int main()
{
C o;
o.f();
}
A::f()
实现是C类的“隐藏”,它为f()
提供了自己的实现-有效地使A::f()
变得毫无意义。在这样的类层次结构设计中我看不到什么价值,但是我的问题是这是有效的C ++还是仅仅是“有效的”(例如未定义的行为)?
答案 0 :(得分:22)
该标准明确允许并支持(例如,参见this在线C ++标准草案),因此显然不是不确定的行为:
10.4抽象类
5 [注意:抽象类可以从非抽象类派生。 抽象,纯虚拟函数可能会覆盖虚拟函数 这不是纯粹的。 —尾注]
结果是您的类B
变成了抽象,并且任何子类(如果也不应是抽象的)都必须定义f()
;仍然可以通过A
调用类A::f()
中的实现,因此-从重用实现的角度来看-不是没有意义的。
答案 1 :(得分:3)
这将安全地实现要求C
的作者为f()
提供实现的目标。
我会问为什么需要这样做-如果基本实现在您的设计中不是“有效”,那么它为什么存在,和/或为什么virtual
?
无论如何,他们仍然可以调用A::f()
,因此是否可以将其视为“隐藏”尚有争议。
答案 2 :(得分:2)
我的问题是这是有效的C ++还是仅仅是“有效的”(例如未定义的行为)?
程序的行为已明确定义。
有效地使
A::f()
变得毫无意义。
当然,如果您从不调用函数,则确实不需要定义函数。为了明确起见,如果您确实选择忽略定义,则必须将函数声明为纯虚函数(反之则不成立;您可以可以定义纯虚函数)。
答案 3 :(得分:2)
这是有效且定义明确的C ++。
如果您想强制您的类的用户实现已经在基类中实现的方法(并且不想使用其他名称,这将是一个更明显的选择),它有时会很有用。实现操作系统消息泵的GUI库是一个应用程序。
答案 4 :(得分:2)
据我所知,没有未定义的行为= 0仅表示派生类必须覆盖它。但是您仍然可以在同一类中为该函数提供离线定义。