问题
I have abstract class A, from which I inherit a number of classes. In the derived classes I am trying to access protected function in A trough A pointer. But I get a compiler error.
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
D(A* aa) :mAPtr(aa){}
void g();
protected:
virtual void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
void D::f(){ }
void D::g()
{
mAPtr->f();
}
The compiler error says : cannot access protected member A::f declared in class A.
If I declare mAPtr to be D*, instead A* everything compiles. And I don't understand why is this.
回答1:
Relying on private
access works on unrelated instances of the same type.
Relying on protected
access works on unrelated instances of the same type (and of more derived types).
However, relying on protected
access does not work on unrelated instances of a base type.
[n3290: 11.5/1]:
When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11. Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).
So D
or something derived from D
, but not A
.
It's an oft-questioned cute oddity about C++ that nonetheless is designed to try to avoid pitfalls. After all, you don't know what type *mAPtr
really has.
回答2:
A class containing a protected section means that this class allows derived classes to manipulate their base class in any way they choose (as far as the protected interface allows).
Class D objects can manipulate their own A part. In doing say they probably want to maintain some invariants.
Suppose there is (or will be in the future!) another class E, also inherited from A. Class E objects also can manipulate their own A part, and they may be enforcing different invariants.
Now, if a class D object was allowed to manipulate the A part of any object, it can't ensure the invariants. A D object may do something to the A part of an E object that breaks that E object. That's why it is not allowed.
But if you really want to, perhaps a way to call A::f, without exposing it to everybody, would be via a friend function.
class A;
namespace detail
{
void call_f(A*);
}
class A
{
friend void detail::call_f(A*);
private:
virtual void f() = 0;
};
namespace detail
{
void call_f(A* a) { a->f(); }
}
class D: public A
{
public:
void g() { detail::call_f(mAPtr); }
private:
void f() {}
A* mAPtr;
};
This relies on users being disciplined enough to stay out of namespaces whose name clearly indicates that it contains implementation details.
回答3:
You forgot using ;
after class declaration:
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
void g();
protected:
void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
Besides, you don't need to store base class pointer.
来源:https://stackoverflow.com/questions/7711237/how-to-access-protected-base-class-function-from-derived-class-through-base-cla