Protected member function address in derived class

2020-03-13 06:22发布

问题:

#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?

回答1:

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.



回答2:

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



回答3:

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();
}