views:

158

answers:

3

The following code gives an compilation error for void b() { m = &A::a; }; stating that A::a() is protected. (Which it is - but that should be no problem)
However the compiler doesn't care when I write B::a(). Even though both mean the same I would prefer A::a() because it states explicitely that a() is defined in A.

So what is the reason why A::a() is forbidden?
EDIT
Maybe someone can find an example that would be problematic if A::a() was allowed in B::b(). If there is such an example, I will mark it as answer to the question.
/EDIT

#include <iostream>
#include <iomanip>
#include <string>
#include <cstdio>

class A {
protected:
  void a(){ std::cout << "A::a()" << std::endl; };
};

typedef void (A::*f)();
class B : public A {
public:
  void b() { m = &A::a; }; // wont compile
  // void b() { m = &B::a; }; // works fine
  void c() { (this->*m)(); };
protected:
  f m;
};

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

// compile with
// g++ -Wall main.cpp -o main

Explanation of the code:
In B I want to store a function pointer to a method in A to be able to call that later in B::c(). And yes, this happens in real life too. :-)

+2  A: 

Because otherwise the outside world can find this protected member: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11174.

See also http://gcc.gnu.org/ml/gcc-patches/2004-06/msg00610.html.

KennyTM
Hmm, in my ignorance I still can't see why it is necessary. The function-pointer and thus the method is still protected in B. So it is not accessible from outside and if it was so would `B::b()` or am I missing the point completely?
tuner
@tuner07, access protection is determined by the static type of the expression. The actual context in which you take the function-pointer doesn't come into play.
Georg Fritzsche
@gf If the access protection is determined by the static type of the expression it shouldn't be possible to call `A::a()` anywhere in B. But that is possible. So the rule applies only to the case where a function is stored into a function-pointer. I can still see no reason why `A::a()` must be prevented by the compiler.
tuner
A: 

You try to access protected member through global namespace (A::a is ::A::a here), use B::A::a instead.

Tele
this still doesn't work. at least with gcc-3.4.4.
tuner
Checked it with gcc 4.4.1, doesn't work (I suppose it breaks the standard here). MS VC++ 9.0 compiles it. Anyway, you should use name of derived class, so B::a is enough.
Tele
+1  A: 

The reason should be similar to why you can't do this in B either:

class B: public A
{
    //...
    void foo(A& x) {
        x.a(); //error
    }

    void foo(B& x) {
        x.a(); //OK
    }
};

That protected doesn't mean that B can access the A part of any class as long it is an A / derived from A. The protected stuff is only available for this and other instances of B.

visitor