I have the following classes with a "reset" functionality.
The base class resets some things which are for all derived classes the same. This code should stay in the base class, so new childs don’t have to reimplement it.
The derived class must implement its own reset function where it can put reset-code which is specific for this derived class.
#include <iostream>
class Base
{
public:
Base(){}
virtual ~Base()
{
std::cerr << __FUNCTION__ << std::endl;
resetBase();
}
virtual void reset() = 0;
protected:
void resetBase()
{
// reset actions which are the same for all derived classes
std::cerr << "Base::" << __FUNCTION__ << std::endl;
}
};
class A : public Base
{
public:
A(){}
~A()
{
std::cerr << __FUNCTION__ << std::endl;
}
void reset() override
{
resetBase();
std::cerr << "A::" << __FUNCTION__ << std::endl;
// reset actions which are specific for this derived class
mValueA = -1;
}
private:
int mValueA = 0;
};
int main()
{
Base* a = new A{};
a->reset();
delete a;
}
Output:
Base::resetBase
A::reset
~A
~Base
Base::resetBase
The code works, but I’m unsatisfied with the design.
I see the following problems:
- If objects are deleted, only the resetBase() function is called. This is currently not so bad, since the objects are destroyed anyway. But it would be nicer if the reset function from the derived class would be called automatically anyway.
- Every new child class has to make sure to call resetBase() in its reset() function. It would be nice if this happens automatically.
Is there a better way to extend a base reset functionality?
>Solution :
We can change your design to automate the resetBase() call using the "non-virtual interface" (NVI) idiom.
The NVI idea is to make the interface of a class non-virtual and then delegate to one or more pure virtual functions for the implementation, allowing the base class to ensure some invariant or common code is always executed, without requiring derived classes to remember to do so and stuff.
Appllying this idea in your case:
#include <iostream>
class Base
{
public:
Base() {}
virtual ~Base()
{
std::cerr << __FUNCTION__ << std::endl;
resetBase();
}
void reset()
{
resetBase();
doReset();
}
protected:
virtual void doReset() = 0;
private:
void resetBase()
{
std::cerr << "Base::" << __FUNCTION__ << std::endl;
}
};
class A : public Base
{
public:
A() {}
~A()
{
std::cerr << __FUNCTION__ << std::endl;
}
protected:
void doReset() override
{
std::cerr << "A::" << __FUNCTION__ << std::endl;
mValueA = -1;
}
private:
int mValueA = 0;
};
int main()
{
Base* a = new A{};
a->reset();
delete a;
return 0;
}
The common resetBase() code is always run and the derived classes only have to implement resetImpl() for their specific reset functionality. Also the destructor of the base class doesn’t need to call resetBase() any longer.