views:

180

answers:

2

I'm confused about the errors generated by the following code. In Derived::doStuff, I can access Base::output directly by calling it.

Why can't I create a pointer to output() in the same context that I can call output()?

(I thought protected / private governed whether you could use a name in a specific context, but apparently that is incomplete?)

Is my fix of writing callback(this, &Derived::output); instead of callback(this, Base::output) the correct solution?

#include <iostream>
using std::cout; using std::endl;

template <typename T, typename U>
void callback(T obj, U func)
{
  ((obj)->*(func))();
}

class Base
{
protected:
  void output() { cout << "Base::output" << endl; }
};

class Derived : public Base
{
public:
  void doStuff()
  {
// call it directly:
    output();
    Base::output();

// create a pointer to it:
//    void (Base::*basePointer)() = &Base::output;
// error: 'void Base::output()' is protected within this context
    void (Derived::*derivedPointer)() = &Derived::output;

// call a function passing the pointer:
//    callback(this, &Base::output);
// error: 'void Base::output()' is protected within this context
    callback(this, &Derived::output);
  }
};

int main()
{
  Derived d;
  d.doStuff();
}

Edit: I'd love to know where this is in the stardard, but mostly I'm just trying to wrap my head around the concept. I think my problem is that callback doesn't have access to protected members of Derived, but it is able to call Derived::output if you pass it a pointer. How is a protected member of Derived that comes from Derived different from a protected member of Derived that comes from Base?

+1  A: 

Edit: I'm not sure if this is a "Where is this in the standard?" question or a "Why is it designed that way?" question, this answers the latter (I don't have a copy of the standard itself to play with)

I believe this is because a function with protected or friend access to base would be able to circumvent access protection by passing the function pointer to methods which should not have access to base's private members.

In this example, callback does not have access to base, and therefore should not be able to call one of it's private functions.

Billy ONeal
I think my problem is that `callback` doesn't have access to protected members of `Derived` either. How is a protected member of `Derived` that comes from `Derived` different from a protected member of `Derived` that comes from `Base`?
Bill
+2  A: 

In short, it's "because the standard says so." Why? I don't know, I've emailed a couple of the standards guys, but haven't received a response, yet.

Specifically, 11.5.1 (from C++0x FCD):

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)114 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.

Edit:

Also, you'll see that you change the code to the following, according to what the standard specifies, it will compile (and run) cleanly:

void (Base::*derivedPointer)() = &Derived::output;
Nathan Ernst