0

Suppose we have a base class Base with a public interface, and some protected methods that are used to support the public interface. Simplified example:

class Base {
    protected:
    virtual int helper() const = 0;
    
    public:
    virtual void do_work() {
        //By default, just call the helper. Descendants can customize behaviour.
        int x = helper();
        do_something_with_an_int(x);
    }
};

And suppose we have some descendants DerivedA, DerivedB, DerivedC ... that implement this interface.

The reason I want to split up the work in two functions (rather than just use do_work to do everything) is because I want to have a special descendant that might look something like this:

class DescendantWrapper : Base {
    Base *impl;
    int x;
    
    protected:
    int helper() const override {
        x += impl->helper();
    }
    
    public:
    void do_work() override {
        helper();

        if(some_internal_condition()) {
            do_some_other_thing_with_an_int(x);
        } else {
            x = 0;
        }
    }
};

The intention is to allow DescendantWrapper to wrap any descendant of Base, and take the place of that descendant in some other code. Of course, the other code would not be aware that its descendant of Base has been wrapped.

The problem is that a derived class (in this example, DescendantWrapper) cannot call a protected method on an instance of its parent class (in this example, Base::helper()).

One solution is to specifically declare DescendantWrapper as a friend of Base. However, this means that other users of this code couldn't create their own descendant wrappers. Does anyone know an alternative to friend functions in this scenario?

Marco Merlini
  • 875
  • 7
  • 29
  • 1
    Not an alternative to friend, but you could create a class `DescendentWrapperBase` that provides a protected `helper` function with the logic shown in your `DescendantWrapper` class. – fabian Feb 21 '21 at 18:14
  • Oh, and would you have to mark `DescendantWrapperBase` as a friend of `Base`? Quick proof-of-concept: https://godbolt.org/z/nxvjb3 – Marco Merlini Feb 21 '21 at 18:18
  • Yes, indeed there should be a friend relationship between `Base` and `DescendantWrapperBase`. Forgot to mention that in the comment. – fabian Feb 21 '21 at 18:23
  • I like that solution. If you decide to write it as an answer, I'll mark it accepted. – Marco Merlini Feb 21 '21 at 18:28

0 Answers0