I am writing a base class that provides a public update() method. When someone derives from this base class, they must implement a pure virtual method that controls a tiny bit of the behavior of this update. This means that a.) update() needs to be public and b.) update() will need to call the pure virtual method in the derived class (which I make private just for safety).
However, I have just become aware of the possibility that the person writing the derived class could accidentally implement the pure virtual function and call update() inside there. This would lead to an infinite number of function calls, which would only be detected at runtime.
Is there some c++ idiom or keyword that would throw compiler errors if someone tried this?
Here is some example code. The person who wrote Derived didn't break the rules, but the person who wrote DerivedBad did.
#include <iostream>
class Base{
private:
virtual void add_to_sum(int incr) = 0;
public:
Base() : m_sum(0), m_other(0) {}
void update(int incr, double other){
this->add_to_sum(incr);
m_other = other;
}
void print_everything() const{
std::cout << "sum: " << m_sum << "\n";
std::cout << "other: " << m_other << "\n";
}
protected:
int m_sum;
private:
double m_other;
};
class Derived : public Base{
virtual void add_to_sum(int incr) override{
this->m_sum += incr;
}
};
class DerivedBad : public Base{
virtual void add_to_sum(int incr) override{
this->m_sum += incr;
this->update(incr, 3.0); // BAD!
}
};
int main() {
// Derived d;
DerivedBad d;
d.update(3, 42);
d.print_everything();
return 0;
}
The language itself can't help you here — a
publicmethod is public, nothing can prevent anyone from using it.Documentation is good — you can mention this problem as a pitfall, but of course users will find other ways to shoot themselves in the foot.
Another way would be to rename your
updatemethod: the generic name doesn't say what the method does, so users will say "I don't really know what it does, but oneupdatetoo many is better than nothing at all". If you give it a longer and a more specific name, maybe it will not make sense to call it from derived classes.Another idea for naming: if the public method is called
update_alland the overridden methods are all calledupdate_xxx,update_yyy, ..., then it would be less natural to make such a call.You could also hold a dedicated member which says "currently updating", then you can detect this situation at run-time and throw an exception before it enters an infinite recursion.