以下实现了您要求的可观察行为。在A
, non - virtual
fun()
run virtualfun_()
因此可以在 中自定义行为B
,但是任何调用fun()
派生类的人都只会看到非多态版本。
#include <iostream>
using namespace std;
struct A{
void fun(){fun_();}
private:
virtual void fun_() { cout << "A\n"; }
};
struct B:public A{
void fun(){cout<<"B\n";}
private:
virtual void fun_() final { fun(); }
};
struct C:public B{
void fun(){cout<<"C\n";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
c.fun(); // notice that this outputs "C" which I think is what you want
}
如果使用 C++03,您可以简单地省略“final”关键字 - 它只是为了防止在B
派生类中进一步不必要地覆盖虚拟行为,例如C
.
(您可能会发现将此与“非虚拟接口模式”进行对比很有趣 - 请参阅 Sutter 和 Alexandrescu 的 C++ 编码标准,第 39 点)
讨论
A
拥有fun
virtual 意味着在派生类中覆盖它是派生类的必要定制能力,但在派生层次结构中的某个点,实现行为的选择可能已缩小到 1 并提供final
实现并非不合理。
我真正担心的是你隐藏 A
/ ......这很令人不安,好像他们做了不同的事情,那么你的代码可能很难推理或调试。 最终确定虚拟功能的决定意味着确定没有必要进行这种进一步的定制。从// /开始工作的代码会做一件事,而在静态已知对象类型的地方,行为可能会有所不同。模板化代码是一个很容易被调用的地方,而模板作者或用户并没有意识到这一点。为了评估这对您来说是否是真正的危险,这将有助于了解“乐趣”的功能目的是什么,以及实现之间可能有何不同,B
fun()
C::fun
B
A*
A&
B*
B&
C
C::fun
A
B
和C
....