1

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;
}
7
  • 2
    Nothing I can think of other than "Document the <expletive deleted> out of it." Commented Jan 25, 2024 at 19:22
  • 2
    As far as I know, the pure virtual method you're trying to protect should be 'protected' rather than 'private'. Commented Jan 25, 2024 at 19:27
  • 1
    @FCo Not necessary. The derived classes are implementing add_to_sum, not calling it. If there was a good way to prevent the derived classes from calling their own function as well, it would probably be time well spent. Commented Jan 25, 2024 at 19:38
  • 1
    @Taylor -- generally speaking, having that much coupling between a base class and derived classes is a bad idea. You'll spend all your time fielding support questions asking for additional options. Commented Jan 25, 2024 at 20:05
  • 1
    You could declare the method as private and make entities that need to use the method as a friend. Remember, if a method is public, any function or class instance can access it including children and other generations. Commented Jan 25, 2024 at 20:09

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.