Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to protected member through member-pointer: is it a hack?

We all know members specified protected from a base class can only be accessed from a derived class own instance. This is a feature from the Standard, and this has been discussed on Stack Overflow multiple times:

But it seems possible to walk around this restriction with member pointers, as user chtz has shown me:

struct Base { protected: int value; }; struct Derived : Base {     void f(Base const& other)     {         //int n = other.value; // error: 'int Base::value' is protected within this context         int n = other.*(&Derived::value); // ok??? why?         (void) n;     } }; 

Live demo on coliru

Why is this possible, is it a wanted feature or a glitch somewhere in the implementation or the wording of the Standard?


From comments emerged another question: if Derived::f is called with an actual Base, is it undefined behaviour?

like image 211
YSC Avatar asked Mar 29 '18 07:03

YSC


People also ask

Can a protected member be accessed?

Protected members in a class are similar to private members as they cannot be accessed from outside the class. But they can be accessed by derived classes or child classes while private members cannot.

Can we access protected member derived class in C#?

A protected member of a base class is accessible in a derived class only if the access takes place through the derived class type.

What is a protected member function?

A protected member variable or function is very similar to a private member but it provided one additional benefit that they can be accessed in child classes which are called derived classes.

Which non member function can access protected members of a class?

B. Friend function can access protected data members of the class.


2 Answers

The fact that a member is not accessible using class member access expr.ref (aclass.amember) due to access control [class.access] does not make this member inaccessible using other expressions.

The expression &Derived::value (whose type is int Base::*) is perfectly standard compliant, and it designates the member value of Base. Then the expression a_base.*p where p is a pointer to a member of Base and a_base an instance of Base is also standard compliant.

So any standard compliant compiler shall make the expression other.*(&Derived::value); defined behavior: access the member value of other.

like image 163
Oliv Avatar answered Sep 19 '22 10:09

Oliv


is it a hack?

In similar vein to using reinterpret_cast, this can be dangerous and may potentially be a source of hard to find bugs. But it's well formed and there's no doubt whether it should work.

To clarify the analogy: The behaviour of reinterpret_cast is also specified exactly in the standard and can be used without any UB. But reinterpret_cast circumvents the type system, and the type system is there for a reason. Similarly, this pointer to member trick is well formed according to the standard, but it circumvents the encapsulation of members, and that encapsulation (typically) exists for a reason (I say typically, since I suppose a programmer can use encapsulation frivolously).

[Is it] a glitch somewhere in the implementation or the wording of the Standard?

No, the implementation is correct. This is how the language has been specified to work.

Member function of Derived can obviously access &Derived::value, since it is a protected member of a base.

The result of that operation is a pointer to a member of Base. This can be applied to a reference to Base. Member access privileges does not apply to pointers to members: It applies only to the names of the members.


From comments emerged another question: if Derived::f is called with an actual Base, is it undefined behaviour?

Not UB. Base has the member.

like image 33
eerorika Avatar answered Sep 21 '22 10:09

eerorika