The Non-virtual Interface idiome (NVI) is pretty self explanatory: You don't write public virtual
functions, but public
functions that call a private virtual
implementation function, like so:
class Object{
virtual void v_load();
public:
void load(){ v_load(); }
}
This enables you, the base class author, to check and enforce pre- and post-conditions or apply other functions so the author of deriving classes can't forget about them.
Now when you are the deriving author, you may want to write a base class yourself - let's call it Pawn
- that extends on the functionality of load()
and therefore has to override v_load()
. But now you are facing a problem:
When you override v_load()
, other clients that want to derive from your class, will always overwrite that behaviour, and they can not call Pawn::v_load()
because it is a private
function, neither can they call Pawn::load()
because it is defined as { v_load; }
in Object
which will of course lead to an infinite loop. Additionally, requiring them to do so could lead to mistakes when they forget that call. If I would want them to enable that, I would have to specify the acces to v_load()
as protected
in Object
, which seems like an ugly solution as it would weaken the encapsulation of Object
greatly.
You could of course still override v_load()
to call a new function v_pawnLoad()
, which is then overridden by clients, but that seems very error-prone as a lot of clients will probably overload the wrong function.
So, how can I design Pawn
in such a way that clients can still override v_load()
while keeping the ability to check pre-conditions or call other functions and (if possible) not enabling, let alone requiring clients of Object
or Pawn
to call the base v_load()
implementation?
load
's behaviour, then put the code you currently have in v_load
in load
then call an empty v_load
in the end.v_load
protected
if you want to let people choose between "replacing" or "extending".As a bonus, in all these 3 variants you can change "allow" with "force" by making your v_load
a pure virtual if you have no default behaviour.
If you wish to limit the override to your Pawn
child class, add the final
keyword to v_load
in Pawn
and use another virtual function to allow children of Pawn
to customise its behaviour.