9
#include <iostream>

class A {
protected:
    void foo()
    {}
};

class B : public A {
public:
    void bar()
    {
       std::cout << (&A::foo) << std::endl;
    }
};

int main()
{
    B b;
    b.bar();
}

Here I am trying to get address of protected member function of base class. I am getting this error.

main.cpp: In member function ‘void B::bar()’:
main.cpp:5: error: ‘void A::foo()’ is protected
main.cpp:13: error: within this context
make: *** [all] Error 1

Changing foo to public works. Also printing &B::foo works. Can you please explain why we can't get address of protected member function of base class?

Ashot
  • 10,807
  • 14
  • 66
  • 117

3 Answers3

9

B is allowed to access protected members of A as long as the access is performed through an object of type B. In your example you're trying to access foo through A, and in that context it is irrelevant whether B derives from A or not.

From N3337, §11.4/1 [class.protected]

An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2) As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C. [Example:

 class B {
 protected:
   int i;
   static int j;
 };
 class D1 : public B {
 };
 class D2 : public B {
   friend void fr(B*,D1*,D2*);
   void mem(B*,D1*);
 };
 // ...
 void D2::mem(B* pb, D1* p1) {
   // ...
   int B::* pmi_B = &B::i; // ill-formed
   int B::* pmi_B2 = &D2::i; // OK
   // ...
 }
 // ...

—end example]

Your example is very similar to the code in D2::mem, which shows that trying to form a pointer to a protected member through B instead of D2 is ill-formed.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Can someone explain the syntax `int B::* pmi_B`? Are `pmi_B` and `pmi_B2` int values or are they pointers? Why do you called `B::` before the asterisk? – Sterling Mar 07 '17 at 18:56
  • 1
    @Sterling It's a [pointer to data member of class B](http://stackoverflow.com/a/670744/241631) – Praetorian Mar 07 '17 at 19:20
0

Seems I found the answer. If we could get pointer of member function we can call it for other objects of type A (not this) which is not allowed.

It is not allowed to call protected member function in derived classes for objects other than this. Getting pointer would violent that.

We can do something like this:

#include <iostream>

class A {
protected:
    void foo()
    {}
};

class B : public A {
public:
    void bar()
    {
        void (A::*fptr)() = &A::foo;

        A obj;
        (obj.*fptr)();

        // obj.foo(); //this is not compiled too.    
    }
};

int main()
{
    B b;
    b.bar();
}
Ashot
  • 10,807
  • 14
  • 66
  • 117
0

I was curious and tried the following example:

#include <iostream>
using namespace std;

class A {
public:
    void foo()
    {
    }
};

class B : public A {
public:
    void bar()
    {
       printf("%p\n", (&A::foo));
       printf("%p\n", (&B::foo));
    }
};

int main()
{
    B b;
    b.bar();
}

Actually, I see that &A::foo == &B::foo, so for protected member of base class you can use derived class member to take address. I suppose in case of virtual functions this will not work

VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • Your example doesn't have protected members. Change `public` to `protected` in `A` and it no longer compiles. So, your statement *you can use derived class member to take address* is wrong. – GreenScape Jun 30 '22 at 15:42