The simplest route is to have only one function, calibrate
that is virtual and overridden by subclasses of Calibration
.
For this I prefer and demonstrate a pure virtual function. The compiler will catch the mistake if a subclass does not implement pure virtual calibration
. If pure virtual is not the right choice for your class hierarchy, define the children's calibrate
methods as void calibrate() override;
to catch future mistakes should the calibrate
method be changed and no longer match.
There is a strong case to be made for making calibrate
a protected function so that it cannot be called directly, forcing Calibration
's users to use the init function and ensuring the device is fully initialized.
To keep the following code clean, I have removed the unused functions.
#include <iostream>
class Calibration {
public:
virtual ~Calibration() {}; // must specify virtual destructor to ensure
// proper destruction of all classes involved
void init();
virtual void calibrate() = 0; // pure virtual function must be implemented
// by children or compile will fail
};
// two subclasses to demonstrate
class Automatic : public Calibration {
private:
void config(); // called through calibrate so should not be directly exposed
public:
void calibrate(); // implements Calibration::calibrate
};
class Manual : public Calibration {
public:
void calibrate(); // implements Calibration::calibrate
};
//Implement functions
void Calibration::init()
{
calibrate(); //calls calibrate function implemented by subclasses
}
//Automatic uses calibrate to call config to keep Calibration's interface simple
void Automatic::calibrate()
{
std::cout << "called Automatic::calibrate" << std::endl;
config();
}
void Automatic::config()
{
std::cout << "called Automatic::config" << std::endl;
}
//Manual uses calibrate to do whatever manual needs to do to calibrate
void Manual::calibrate()
{
std::cout << "called Manual::calibrate" << std::endl;
}
//demonstration
int main()
{
Automatic a;
a.init(); // can directly init an Automatic.
// This will call Calibrate::init, which will then call the correct calibrate
Manual m;
m.init(); // or a manual
Calibration * c = new Automatic();
c->init(); // magic of polymorphism calls correct calibrate
delete c;
c = new Manual();
c->init();
delete c;
}