Policy Inheritance and Inaccessible Protected Members

It seems that the protected member from the template policy class is not available, even with a class hierarchy that seems correct.

For example, with the following code snippet:

#include <iostream> using namespace std; template <class T> class A { protected: T value; T getValue() { return value; } public: A(T value) { this->value = value; } }; template <class T, template <class U> class A> class B : protected A<T> { public: B() : A<T>(0) { /* Fake value */ } void print(A<T>& input) { cout << input.getValue() << endl; } }; int main(int argc, char *argv[]) { B<int, A> b; A<int> a(42); b.print(a); } 

The compiler (clang OS X, but gcc returns the same type of error) returns the following error:

 Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>' cout << input.getValue() << endl; ^ Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here b.print(a); ^ Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>' T getValue() { return value; } ^ 1 error generated. 

It is strange that the last note of the compiler is absolutely correct, but it is already applied, since the object b is of type 'B<int, A>' . Is this a compiler error or is there a problem in the code?

thanks

+6
source share
4 answers

Stop for a moment about the template and look at this:

  class A { protected: int value; int getValue() { return value; } public: A(int value) { this->value = value; } }; class B : protected A { public: B() : A(0) { /* Fake value */ } void print(A& input) { cout << input.getValue() << endl; } }; 

The implementation of the print() method is incorrect because you cannot access non-public member A inside B . And here's why: from inside B you can only access non-public members of B These members can either be inherited or not - it does not matter.

A& input , on the other hand, may not be a reference to instance B This may be a reference to another subclass (which may have getValue() inaccessible).

+6
source

You misunderstood the meaning of secure access.

Protected members are called by derived classes. But only on the base object contained within the class itself.

For example, if I simplified the problem using:

 class A { protected: void getValue(){} }; class B : protected A { public: void print(A& input) { input.getValue(); //Invallid } }; 

getValue cannot be called on object "A" other than object "A" inside the class itself. This, for example, is valid.

  void print() { getValue(); //Valid, calling the base class getValue() } 

As Dan Nissenbaum and Shakurov noted. This is also true:

 void print(B& input) { input.getValue(); } 

This is because we explicitly say that the input is object B. And the compiler knows that all objects B protect access to getValue. In the case where we pass A &, the object may be somewhat similar to type C, which can be moved from A with private access.

+9
source

Do not be distracted by the template. This has nothing to do with the error. The line in main that the compiler complains about creates an object of type B<int, a> and tries to access the protected member. This is not legal, regardless of type. You can only use protected members from within a member function or a friend function. For instance:

 struct S { protected: void f(); }; int main() { S s; sf(); // error: attempts to call a protected member function } 
+2
source

The member functions of a derived class have access to the protected elements of the base class within any object of its type that is passed as an argument if the explicitly declared class of the object passed as an argument is in the form of a derived class (or another derived class).

Objects explicitly passed as a type of base class cannot access protected members within member functions of a derived class.

In other words, if we have:

 class A { protected: int x; } class B : public A { void foo(B b) { bx; // allowed because 'b' is explicitly declared as an object of class B } void goo(A a) { ax; // error because 'a' is explicitly declared as having *base* class type } }; 

... then the string ax invalid because the explicit type of argument A , but the rule for secure access applies only to objects explicitly defined as the same class as trying to access a member. (... or a class derived from it, i.e. if class C comes from B , then passing the object explicitly declared as an object of class C will also have x available inside B member functions.)

The reason for this is given by Shakurov when he writes (rephrasing)

A & input may not be a reference to instance B. This may be a reference to another subclass (which may have getValue () not available)

It also provides an excellent explanation for this answer: access to a protected member of a base class in another subclass .

As an interest, I believe this comes from the C ++ standard:

11.4 Protected Member Access [class.protected] 1 The optional outside access control described in Section 11 above applies when a non-static data element or non-static member function is a protected member of its naming class (11.2) 115 As described above, access to a protected member is provided because the link is found by a friend or a member of a class C. If access is by forming a pointer to a member (5.3.1), the naming specifier must denote C or the class derived from C. All other calls include ( You can, implicit) (5.2.5). In this case, the class of the expression object must be C or a class derived from C.

+2
source

All Articles