Preventing Derived Class calling Base class's public method

84 Views Asked by At

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

There are 1 best solutions below

0
anatolyg On

The language itself can't help you here — a public method 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 update method: the generic name doesn't say what the method does, so users will say "I don't really know what it does, but one update too 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_all and the overridden methods are all called update_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.