Archived

This topic is now archived and is closed to further replies.

Kylotan

'protected' confusion in C++

Recommended Posts

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 ]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.



Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
Protected has its place... usually for functions rather than data, I admit. In my case, each Creature has a protected ''direction'' variable and the subclasses ''Player'' and ''Monster'' use it. The example I posted arose because a Monster member function gets a reference to a Creature passed in, and was trying to access the direction from that. Which it can''t. And I''m not yet sure which is the cleanest way to fix this problem.

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

Share this post


Link to post
Share on other sites
quote:
Original post by MadKeithV
PublicChild would gain access to the
now-private m_protVar of PrivateChild, which is a serious data
security risk.

Grr. Thanks... that makes sense, but I would never have thought of it myself, because I never use private inheritance.



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

Share this post


Link to post
Share on other sites
quote:
Original post by Kylotan
Thanks for the clarification, Sabreman. I still don''t quite understand the motivation for the decision

Yeah sorry, the Standard''s not very good for that kind of thing, and I missed that you were looking for "why" aswell as "what". I think MadKeithV hinted at the motivation. It''s a question of type-safety. Basically, if you have an inheritance tree which looks like:


  
class base
{
//... stuff ...

};

class derived1 : public base
{
//... stuff ...

};

class derived2 : public base
{
// ... stuff ...

void f(base& b)
{
// ...

}
};


Then, allowing access to b''s protected members in f() opens up the possibility of modifying the internals of a derived1, which derived2 should not have access to do. The added restrictions of 11.5 ensure that any such attempts at modifying protected data are done via the correct type.

Share this post


Link to post
Share on other sites
Ok, thanks. So I''m gonna have to use ''friend'' here, if I want to keep this data protected but allow access to sibling classes via a base pointer/reference... yes?

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

Share this post


Link to post
Share on other sites
I''m not used to c++ but more to java... and it''s quite fun... the example shown at the top works without problem with java!
It makes no difference if it''s a Child, a Parent, or any other Parent-based class, unlike c++!
The concept is the same but is nevertheless different in practice.
And i''ve made the biggest error of you since i thought protected access was restricted to the own instance. This is a good lesson for me !

Share this post


Link to post
Share on other sites
quote:
Original post by Kylotan
Protected has its place... usually for functions rather than data, I admit.

I read an article the other day that pointed out that this pattern:
- base class has pure-virtual protected function
- derive a class for each behavior & override that function

..is really a callback mechanism. I think I agree.

Share this post


Link to post
Share on other sites