I am going through this article http://www.gotw.ca/publications/mill18.htm by Herb Sutter. The author mentions that writing non-virtual interfaces separates the interface sp
When you specify the virtual public interface, int Process( Gadget& );
, you are also restricting the extension interface to match this public interface. Whoever extends this class will need to do this by implementing the Process
function.
Providing a cleaner public interface and a more suitable [batch] of well designed private functions for customization will allow tackling our two goals individually.
By customizable behavior
it means the implementation provided by different Derived Classes
, i.e the classes which will derive from your Interface
.
Consider this:
class IMachine
{
public:
int ProcessJob()
{
cout << "Processing Job in By-Default way" << endl;
}
virtual int ProcessOrder()
{
cout << "Processing Order in By-Default way" << endl;
}
};
class CMachine_A : public IMachine
{
public:
int ProcessJob()
{
cout << "Processing Job in Machine A's way" << endl;
}
int ProcessOrder()
{
cout << "Processing Order in Machine A's way" << endl;
}
};
class CMachine_B : public IMachine
{
public:
int ProcessJob()
{
cout << "Processing Job in Machine B's way" << endl;
}
int ProcessOrder()
{
cout << "Processing Order in Machine B's way" << endl;
}
};
IMachine *pMachine;
CMachine_A oMachineA;
CMachine_B oMachineB;
pMachine = &oMachineA;
pMachine->ProcessJob();
pMachine = &oMachineB;
pMachine->ProcessJob();
Output:
Processing Job in By-Default way
Processing Job in By-Default way
So, in above example even though pMachine
points to different concrete implementations (read: derived classes), the output is same irrespective of chosen implementation/derived class. That is, the customizable behavior
of Machine A and Machine B is not coming in-effect or not honored. So, by having non virtual IMachine::ProcessJob()
, the interface IMachine
has separated/ignored/suppressed the way in which the Job will get processed irrespective of the type of Machine (CMachine_A
or CMachine_B
) which is used.
Now consider this:
IMachine *pMachine;
CMachine_A oMachineA;
CMachine_B oMachineB;
pMachine = &oMachineA;
pMachine->ProcessOrder();
pMachine = &oMachineB;
pMachine->ProcessOrder();
Output:
Processing Order in Machine A's way
Processing Order in Machine B's way
Here, when pMachine
points to different concrete implementations (read: derived classes), the output is according to the chosen implementation/derived class. That is, the customizable behavior
of Machine A and Machine B is coming in-effect or honored. So, by having virtual IMachine::ProcessOrder()
, the interface IMachine
has kept the option/way open in which the Order will get processed depending upon the type of Machine (CMachine_A
or CMachine_B
) which is used.
In short, since the interface IMachine
has kept the ProcessOrder
as virtual
therefore different implementation/derived class can provide customizable behavior
for the function ProcessOrder
.