'protected' confusion in C++

Started by
15 comments, last by Kylotan 21 years, 7 months ago
This code:

class Parent
{
protected:
    int protVar;
};


class Child : public Parent
{
private:
    void function(const Parent& ref);
};


void Child::function(const Parent& ref)
{
    int x = this->protVar;
    int y = ref.protVar;
} 
Gives an error: namely, that the last expression "ref.protVar" is invalid because protVar is protected. But I thought protected allowed Child classes to see it? Why is it protecting the other instance? As far as I knew, private and protected were on a per-class basis, not a per-instance basis. After all, you don''t have to use accessors when writing overloaded operators, for example. The fact that the operator is part of the class allows you to access private and protected members of another class of the same type. Is this therefore just an exception for classes of identical type to be able to see the protected members of other instances? My understanding must be wrong, since both GCC and MSVC tell me my code won''t work, but it seems very inconsistent... either protected should work on a per-class basis or a per-instance basis, and yet it seems to work per-class when it''s the same class and per-instance when it''s a derived one. Or to put it another way: ClassA instance 1 can access a private variable of ClassA instance 2, but can''t access ClassA instance 2''s protected variables it inherited from ClassA''s parent. Why? Can anyone correct my logic here? [ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]
Advertisement
The Standard''s probably a good place to start:

quote:
protected; that is, its name can be used only be members and friends of the class in which it is declared, and by members and friends of classes derived from this class.


Which is in line with what you''ve said. Additionally, section 11.5 of the Standard gives:

quote:
When a friend or a member function of a derived class references a protected nonstatic 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, the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class).


The emboldened text highlights the key-phrase in the paragraph which should clear up your confusion.
quote:Original post by Kylotan
Or to put it another way: ClassA instance 1 can access a private variable of ClassA instance 2, but can''t access ClassA instance 2''s protected variables it inherited from ClassA''s parent. Why?

It can. But you try to access members of the Parent class, not of the same class (Child).

This will work:
class Parent{protected:    int protVar;};class Child : public Parent{private:    void function(const Child& ref);};void Child::function(const Child& ref){    int x = this->protVar;    int y = ref.protVar;}  

The other possibility would be to declare Parent as a friend.
quote:Original post by Origin
The other possibility would be to declare Parent as a friend.


To declare Child as friend in Parent you mean?

Yeah this question threw me at first, but I looked it up and tweaked it and realised that the Parent reference is not guaranteed to point to a Child, or even to a derived class of Parent that preserves the access rights (class Child2 : private Parent !! ), therefore cannot be allowed access to the protected member variable.



It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
quote:Original post by Kylotan
Gives an error: namely, that the last expression "ref.protVar" is invalid because protVar is protected. But I thought protected allowed Child classes to see it? Why is it protecting the other instance? ...

Damn, and i thought moderators where pros !

quote:Original post by MadKeithV
To declare Child as friend in Parent you mean?

Yeah this question threw me at first, but I looked it up and tweaked it and realised that the Parent reference is not guaranteed to point to a Child, or even to a derived class of Parent that preserves the access rights (class Child2 : private Parent !! ), therefore cannot be allowed access to the protected member variable.

And you're right MadKeithV: it's absolutely not a secure way to do it. It's a quick but dirty way to resolve the problem.
this solution was only proposed for the example given, and only for it. It's trivial that the 'ref' MUST be a 'Parent' class when declaring it friend.

The other solution proposed by him is good (but maybe doesn't fit to the problem).

[edited by - misterX on September 3, 2002 8:29:42 AM]
quote:Original post by misterX

Am i an idiot, or is it again a big stupid mistake ?!!!
This won''t work too !!! The variable is still protected and can''t be accessed from ouside !!!


I won''t make any judgements , but the Child ref example is correct. Now, the reference is guaranteed to be a Child (or derived from Child), and therefore qualifies to allow access to the protected member variable.

Look at it like this: Child has access to protected members of Children. Because Child is publically derived from Parent, the protected members of Parent become protected members of Child. Hence, an access to a protected member originally declared in Parent is allowed. Access to protected members of other Child objects is also allowed (and through the same mechanism, to classes publically derived from Child). It does NOT extend however to objects of the Parent class, or classes derived from the Parent class that are not Child.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
Yeah, i''m very sorry, i''m the idiot !
quote:Original post by misterX
Damn, and i thought moderators where pros !

Hey, I think that's a little unfair! I know what protected means, but if you take the fact that you can inspect another instance's private variables, it would make sense that you can inspect another instance's protected variables when you derive from that class... after all, the implementation is already available to the current class.

Thanks for the clarification, Sabreman. I don't quite understand the motivation for the decision, but I'm sure it makes sense to someone who knows more than I do.

EDIT: Rewritten to say what I meant rather than something else entirely...

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]

[edited by - Kylotan on September 3, 2002 8:37:33 AM]
Heh, nobody''s an idiot, I had to look the original example up and try it out to figure out why it wouldn''t work. But now I realise why, and it probably won''t catch me again.

You''d have a tough time catching me declaring ANY member variable protected, in fact... I hardly ever do that these days, private only.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
quote:Original post by Kylotan
Thanks for the clarification, Sabreman. I still don't quite understand the motivation for the decision, but I'm sure it makes sense to someone who knows more than I do.


Let me try to demonstrate by example:

    class Parent{protected:  int  m_protVar;};class PublicChild : public Parent{private:void function( const Parent& r ) {    int s = r.m_protVar;  // Error!  }};class PrivateChild : private Parent{};int main( void ){PublicChild c1;PrivateChild c2;c1.function( c2 ); // PublicChild would gain access to the// now-private m_protVar of PrivateChild, which is a serious data// security risk.  Hence, Child can only override the access// specifiers on objects of its own class or derived from its own// class}    


[edit]Missed one brace



[edited by - MadKeithV on September 3, 2002 8:43:25 AM]
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.

This topic is closed to new replies.

Advertisement