Non-virtual interface idiom (NVI)
In almost every cases, it’s recommended to follow OOAD
principles, but sometimes we should try to look some other alternatives, provided
by programming languages, which could be a better options for certain situations.
In C++, we can implement virtual function in private and we
can redefine its behavior in derived class's private and it will work in same way(did you try that?).
When we define virtual function as private and expose a
non-virtual public function to outer world, we call it “non-virtual interface
idiom”. Non-virtual public function will internally call virtual function, in
other words you are not exposing your virtual function to client.
You will achieve high encapsulation, plus we can add pre and
post execution/condition in the body of non-virtual public function. Call some set of
functions, as prerequisite of calling virtual function, and after call returns
from virtual function, again call some set of function as part of post cleanups/conditions,
according to your need.
C++ implementation of NVI -
/**************************************************************************************
/* The template method pattern via the non-Virtual interface idiom.
/* or say -> non-virtual interface idiom (NVI)
***************************************************************************************/
//*************************************************************************************
// Header files
#include<iostream>
using namespace std;
//*************************************************************************************
//Global variables and functions
//*************************************************************************************
// Class
class GameCharacter {
public:
int HealthValue() const;
private:
virtual int DoHealthValue() const;
};
///////////////////////////////////////////////////////////////////////////////////////
int GameCharacter::HealthValue() const {
cout<<"inside GameCharacter::HealthValue "<<endl;
return DoHealthValue();
}
///////////////////////////////////////////////////////////////////////////////////////
int GameCharacter::DoHealthValue() const {
cout<<"inside GameCharacter::DoHealthValue "<<endl;
return 7; // temp implementation
}
//*************************************************************************************
// Main functions
int main(int argc, char** argv) {
GameCharacter objGameCharacter;
cout<<"HealthValue for objGameCharacter - "<<objGameCharacter.HealthValue();
return 0;
}
///////////////////////////////////////////////////////////////////-------------OutPut
/*
$ ./a.exe
inside GameCharacter::HealthValue
inside GameCharacter::DoHealthValue
HealthValue for objGameCharacter - 7
*/
C++ demonstration of private virtual function implementation in derived class -
/************************************************************************************** /* The template method pattern via the non-Virtual interface idiom. /* or say -> non-virtual interface idiom (NVI) ***************************************************************************************/ //************************************************************************************* // Header files #include<iostream> using namespace std; //************************************************************************************* //Global variables and functions //************************************************************************************* // Class class GameCharacter { public: int HealthValue() const; private: virtual int DoHealthValue() const; }; /////////////////////////////////////////////////////////////////////////////////////// int GameCharacter::HealthValue() const { cout<<"inside GameCharacter::HealthValue "<<endl; return DoHealthValue(); } /////////////////////////////////////////////////////////////////////////////////////// int GameCharacter::DoHealthValue() const { cout<<"inside GameCharacter::DoHealthValue "<<endl; return 7; // temp implementation } //************************************************************************************* // Main functions int main(int argc, char** argv) { GameCharacter objGameCharacter; cout<<"HealthValue for objGameCharacter - "<<objGameCharacter.HealthValue(); return 0; } ///////////////////////////////////////////////////////////////////-------------OutPut /* $ ./a.exe inside GameCharacter::HealthValue inside GameCharacter::DoHealthValue HealthValue for objGameCharacter - 7 */
/************************************************************************************** /* Implementing private virtual functions /* /* (c) 2015 Kunjesh Singh Baghel, All Rights Reserved. /* https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************/ //************************************************************************************* // Header files #include<iostream> using namespace std; //************************************************************************************* //Global variables and functions //************************************************************************************* // Class class Base { public: void Display() const; private: virtual void ImpDisplay() const; }; /////////////////////////////////////////////////////////////////////////////////////// void Base::Display() const { cout<<"inside Base::Display "<<endl; ImpDisplay(); } /////////////////////////////////////////////////////////////////////////////////////// void Base::ImpDisplay() const { cout<<"inside Base::ImpDisplay "<<endl; } /////////////////////////////////////////////////////////////////////////////////////// class Derived : public Base { public: using Base::Display; private: virtual void ImpDisplay() const; }; /////////////////////////////////////////////////////////////////////////////////////// void Derived::ImpDisplay() const { cout<<"inside Derived::ImpDisplay "<<endl; } //************************************************************************************* // Main functions int main(int argc, char** argv) { Base *pointerBase; Base objBase; Derived objDerived; pointerBase = &objBase; pointerBase->Display(); pointerBase = &objDerived; pointerBase->Display(); return 0; } ///////////////////////////////////////////////////////////////////-------------OutPut /* $ ./a.exe inside Base::Display inside Base::ImpDisplay inside Base::Display inside Derived::ImpDisplay */
Thanks for reading it. To read more on design patterns and basic design principles please see my web page. You can also join me on FB or on G++. Please drop comments for any question related to this blog.
Comments
Post a Comment