Non-virtual Interface idiome (NVI) 非常不言自明:您不编写public virtual
函数,而是编写public
调用private virtual
实现函数的函数,如下所示:
class Object{
virtual void v_load();
public:
void load(){ v_load(); }
}
这使您(基类作者)能够检查和强制执行前置条件和后置条件或应用其他函数,以便派生类的作者不会忘记它们。
现在,当您是派生作者时,您可能想自己编写一个基类——我们称之为它Pawn
——它扩展了 的功能,load()
因此必须覆盖v_load()
. 但是现在你面临一个问题:
当您覆盖时v_load()
,其他想要从您的类派生的客户端将始终覆盖该行为,并且它们不能调用Pawn::v_load()
,因为它是一个private
函数,它们也不能调用,Pawn::load()
因为它被定义为{ v_load; }
其中Object
当然会导致无限循环. 此外,当他们忘记那个电话时,要求他们这样做可能会导致错误。如果我希望他们启用它,我将不得不指定对v_load()
as protected
in的访问权限Object
,这似乎是一个丑陋的解决方案,因为它会Object
大大削弱 的封装。
当然,您仍然可以覆盖v_load()
以调用新函数v_pawnLoad()
,然后由客户端覆盖,但这似乎很容易出错,因为许多客户端可能会重载错误的函数。
那么,我如何设计Pawn
这样一种方式,即客户端仍然可以覆盖v_load()
,同时保持检查前置条件或调用其他函数的能力,并且(如果可能)不启用,更不用说要求客户端Object
或Pawn
调用基本v_load()
实现了?