4

We can find here and here the explanation of why we can't call protected method of base class on base object from method in derived class, like in this code :

class B {
protected:
    void f ();
};

class D : public B {
public:
    void g (B* other) {
        other->f(); /* Error: B::f() is protected */
    }
};

But are there any solutions? What if we really want to call this base method on this object? After all, there wouldn't be any problem doing this, we can ensure that other is really a B?

Community
  • 1
  • 1
Félix Faisant
  • 191
  • 1
  • 1
  • 11
  • same answer as for calling private method on another class. make it pubic or friend it or think again do you really need to call it? – Bryan Chen May 27 '14 at 23:28
  • Have you tried a friend class? – Stefan May 27 '14 at 23:30
  • 1
    If this is an academic question, you can use friendship to resolve it. If this arises from a real application, you need to question your design. Figure out a better design that does not put you in this fix. – R Sahu May 27 '14 at 23:39
  • The problem of `friend` is modularity. `B` doesn't have to know what classes will subclass it and will use its protected functions. This is not truly a concreate question because I know that I could adopt a different desing. But I se no objections, in my case, about calling base class functions like this. – Félix Faisant May 28 '14 at 16:32

3 Answers3

3

Note: The straight forward (and recommended) way to enable something as this is to make the inherited class a friend of the base class; this means that it will have access to it's protected and private parts.


I wanna bend the rules a little

So you have decided that the rules set forth by the Standard are annoying, you want to do whatever you want, when you want, and the way you want it! Rules are meant to be broken, etc etc.

class B {
  protected:
    void f ();
};

class D : public B {
  public:
    void g (B * other) {
      (other->*&D::f) (); // legal
    }
};

How does this, legal and fully functional, hack work?

Even though the Standard says that we are not allowed to inspect B::f from within D, we are of course allowed to look at D::f; which is the same (inherited) thing, since we didn't declare another f inside D.

Our hack concists of taking the address of D::f, relying on the fact that the type of it really is a pointer to a member function within B, and using this address to call the function upon other.

Another (semantically) equivalent way to write the snippet:

void (B::*hack)() = &D::f; (other->*hack) ();

Note: Technically we are not diving into the protected contents of B, we are merely relying on the fact that the contents accessed through D::f happens to be the same as the one in B::f. We are still playing by the rules set forth by the Standard, it's just that we are somewhat abusing them.

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • 2
    Thanks ! I find your solution quite clean because it doesn't need to modify anithing in the class hierarchy, unlike `friend` solution. – Félix Faisant May 28 '14 at 16:36
  • 1
    I am wondering if there is undefined (or at least unspecified) behavior in this. I would expect it because we are more or less calling a method of type `D` on an object of type `B`. On the other hand, I guess chances are high that this will always work as expected even if UB. – Ignitor Jan 13 '19 at 22:34
1

The better solution would be to declare a static protected function in Base that redirects the call to the private / protected function. This way, we don't break encapsulation because the designer of Base can make an explicit choice to allow all derived classes to call foo on each other, while avoiding to put foo into the public interface or explicitly turning all possible subclasses of Base into friends.

See my answer for the original question with code examples.

Clemens Sielaff
  • 708
  • 10
  • 15
0

You could make class D a friend of class B:

class B {
friend class D;
protected:
    void f ();
};
alain
  • 11,939
  • 2
  • 31
  • 51