|
-
July 12th, 2006, 10:12 AM
#1
overzealous protection rules
The following doesn’t compile:
struct A
{
A* partner;
void doodah()
{ ++partner->value; } //this is legal
protected:
int value;
};
struct B: public A
{
void foobar()
{ partner->value += 2; } //but this isn’t
};
The error is that B::foobar() can’t access partner->value, due to protection, even though B is an A. Now I'm not a language lawyer, but honestly this should work. B is an A; and A can access the protected members of other A's. But B can't??
-
July 12th, 2006, 10:33 AM
#2
Re: overzealous protection rules
I'm not entirely sure why but this works:
Code:
struct B: public A
{
void foobar()
{
value += 2; }
};
Comeau gives this error for the original code
"ComeauTest.c", line 19: error: protected member "A::value" is not accessible through a "A" pointer or object partner->value += 2;
which is more enlightening than Visual Studio.
-Matt
-
July 12th, 2006, 10:35 AM
#3
Re: overzealous protection rules
Well that works because you're accessing B's *own* value member. But I don't want to access that - I want to access the value member of "partner" which is a member of B inherited from A.
-
July 12th, 2006, 10:38 AM
#4
Re: overzealous protection rules
 Originally Posted by blueimpb
The error is that B::foobar() can’t access partner->value, due to protection, even though B is an A.
In the foobar() function, what is the value of this? What is the value of partner? There's your reason -- different objects. You're looking at this at the class level, when you should be looking at it at the object level.
You have two objects there, this and partner -- you don't have one object, regardless of where you placed the declaration of partner.
Regards,
Paul McKenzie
-
July 12th, 2006, 11:54 AM
#5
Re: overzealous protection rules
I know you get a lot of newb's posting but yes, I realize that "partner" and "this" are different. Did the fact that I named it "partner" not make that obvious?
It's extremely common to have a pointer to ANOTHER object of your OWN type. Think about that for a minute...then remember the basic definition of a linked list.
Now imagine the following:
class Node
{
public:
virtual void doSomething() {}
protected:
Node* child;
Node* parent;
};
class Int_Node : public Node
{
int data;
public:
virtual void doSomething()
{
//first, check list validity
if (parent->child != (Node*)this)
cout << "Oh No!";
....
}
};
see the idea?
-
July 12th, 2006, 12:22 PM
#6
Re: overzealous protection rules
There are three levels of access for precisly this reason. Public is accessible by all, protected by derived classes, and private only by the class in which it is declared.
The statement "B IS-A A" is a meta-semantic statement about the use of the public inheritance relationship: it is not a rule of the standard. As far as the standard is concerned, derived classes can only access public and protected members of their base classes. You cannot access the "partner" member of the base class, because it's private to that class. You can access this->value, because value is protected, but you can't access "partner" at all.
This is exactly how it should be.
In your last example, there is no error, since both members are protected and therefore accessible by the derived class. However, this is not good design, since you have introduced excessive coupling between the two classes and you're heading for maintenance problems. The code you've put into the derived class to compare the pointers would be better off in the base class, since it's a base class operation that is dependent on the implementation details of the base class and should be of no concern to the derived class.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
July 13th, 2006, 07:00 AM
#7
Re: overzealous protection rules
The second example is not valid as Int_Node cannot access parent->child.
You are not allowed to access protected members of base-class instances other than your own. The reason is simple - it might not be your type so access should be restricted.
In the example above, Node::parent may not be your type. It could be float_Node. In the first example there could be another class C that derives from A and partner could be of type C.
What you should be doing is not having protected access to members, only to methods. Some of these methods may be virtual so you can override it for the class in question. Thus if partner is of type C, when you call the method from B (a method in your own A, not in partner) it will actually invoke a method defined in C, its own class.
Last edited by NMTop40; July 13th, 2006 at 07:02 AM.
-
July 14th, 2006, 03:00 AM
#8
Re: overzealous protection rules
 Originally Posted by NMTop40
The second example is not valid as Int_Node cannot access parent->child.
Oops. Missed that one.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
July 14th, 2006, 05:22 AM
#9
Re: overzealous protection rules
You are only allowed to access protected members of a base class through your own type. This is to stop you from breaking encasulation for other classes derived from that base class. e.g.
Code:
#include <assert.h>
class A {
protected: int i;
};
class B: public A {
void mutate(A& a) {
a.i = -1;
}
};
class C: public A {
public:
C() {
i = 1;
}
~C() {
assert (i == 1);
}
};
int main() {
C c;
B b;
b.mutate(c);
}
Here, if that were allowed, b would be allowed to break an invariant of class C, namely that i == 1.
For your code, that does of course suggest a solution:
Code:
struct B: public A
{
void foobar()
{
if (B* p = dynamic_cast<B*>(partner))
{
//ok, it's a B (not a C, D or E), so we are allowed to modify its protected parts
//since we know how to modify Bs, given that we are a B!
p->value += 2;
}
}
};
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|