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;
}