Inheritage visibility in C++
Hello.
I'm having problems with the visibility of symbols declared protected.
I have two classes, Spatial and Node (will be a very simplified version of the scenegraph in “3D Game Engine Architectureâ€, by David Eberly)
and
where addChild is implemented like this:
I get the error “void Spatial::set_parent(Spatial*) is protected within this contextâ€.
I can't see what the problem is. Shouldn't protected symbols in base classes be accessible?
I'm having problems with the visibility of symbols declared protected.
I have two classes, Spatial and Node (will be a very simplified version of the scenegraph in “3D Game Engine Architectureâ€, by David Eberly)
Code:
class Spatial {
...
protected:
void set_parent(Spatial* parent_arg);
...
};and
Code:
class Node : public Spatial {
...
public:
addChild(Spatial* child);
...
};where addChild is implemented like this:
Code:
void Node::addChild(Spatial* child) {
if (find(children.begin(), children.end(), child) == children.end()) {
children.push_back(child);
child->set_parent(this);
}
}I get the error “void Spatial::set_parent(Spatial*) is protected within this contextâ€.
I can't see what the problem is. Shouldn't protected symbols in base classes be accessible?
I've had that too, it's XCode not being very clear. The error is split over two lines, right?
void Spatial::set_parent (Spatial*) is protected <-- shows what is protected
within this context <-- shows where you're trying to access it
The two lines jump to differents places in your code.
void Spatial::set_parent (Spatial*) is protected <-- shows what is protected
within this context <-- shows where you're trying to access it
The two lines jump to differents places in your code.
Yes, that's right. It is split over two lines (I originally read it as being the same continued message, but now that you point it out, I see what you mean). That doesn't tell me any more about what the problem is though. Why exactly can't I access a symbol declared protected in a base class? I thought the point of the protected declaration was specifially so that one could use parts of base classes within inheritance trees, but not from the outside.
Thanks for the clarification on the error message though.
Thanks for the clarification on the error message though.
I could be wrong but I don't believe you can call protected methods on a *different* object, even if you're derived from it.
E.g., you could call the inherited protected method if the target object is 'this', but not if it's a different object.
This might call for a refactoring.
E.g., you could call the inherited protected method if the target object is 'this', but not if it's a different object.
This might call for a refactoring.
Wow, do I feel stupid. I didn't even think about that.
Anyway, any suggestions how to do this then without declaring set_parent public?
Anyway, any suggestions how to do this then without declaring set_parent public?
Add this:
...to the body of the class which should be able to call private methods on TheOtherClass.
Code:
friend class TheOtherClass;Quote:I could be wrong but I don't believe you can call protected methods on a *different* object, even if you're derived from it.This can't be true...
Maybe you should make a test case, that would clear things up.
NCarter: Not really general enough, as I want the whole tree of classes to be able to use the functionality.
DDustin: I already made the test case (stripped all code except the code in question), and this seems to be the case. Logical enough, when I think about it. In most circumstances I probably wouldn't want two objects (even of the same class) to be able to use each others protected methods/variables.
DDustin: I already made the test case (stripped all code except the code in question), and this seems to be the case. Logical enough, when I think about it. In most circumstances I probably wouldn't want two objects (even of the same class) to be able to use each others protected methods/variables.
ermitgilsukaru Wrote:In most circumstances I probably wouldn't want two objects (even of the same class) to be able to use each others protected methods/variables.
But they can if those methods are 'private', and (until now...) I believe that 'protected' is weaker protection than 'private'? I'm pretty sure you're wrong...
A little later: I was right, 'protected' is weaker protection than 'private' (or at least, not as strong as you thought); here's a trite little test case of calling a 'protected' method of another object:
Code:
#include <stdio.h>
class MyClass
{
public:
void LittleNicePublic( MyClass *p_obj )
{
p_obj-> BigBadProtected();
};
protected:
void BigBadProtected( void )
{
printf( "Hello from the big bad, and protected method.\n" );
};
};
int main( int argc, char *argv[] )
{
MyClass obj1, obj2;
obj1.LittleNicePublic( &obj2 );
return 0;
}Mark Bishop
Hmmm. I just tried to compile this code:
...and it doesn't work. Sealfin has with his test-code established that within a class two instances have automatic friend status (and when looking at earlier code I've written, I see that is the case). So the problem must have something to do with the rules of inheritance of friend status. (sorry for the convoluted phrasing)
Code:
class Base {
protected: void gaz() { }
};
class Derived : public Base {
public: void foo(Base* bar) { bar->gaz(); }
};
int main(int argc, const char** argv) {
Derived a, b;
a.foo(&b);
}...and it doesn't work. Sealfin has with his test-code established that within a class two instances have automatic friend status (and when looking at earlier code I've written, I see that is the case). So the problem must have something to do with the rules of inheritance of friend status. (sorry for the convoluted phrasing)
ermitgilsukaru, this is your test case with a minor alteration: you needed to upcast (terminology?) to Derived the call to the 'protected' Base method (I presume you meant object 'b' in main() to be of the Base class, but it works either way.)
Code:
#include <stdio.h>
class Base
{
protected:
void gaz()
{
printf( "Bow before the metasyntactic variable names of doom.\n" );
};
};
class Derived : public Base
{
public:
void foo( Base* bar )
{
(( Derived* )bar )->gaz();
};
};
int main( int argc, const char* argv[] )
{
Derived a;
Base b;
a.foo( &b );
return 0;
}Mark Bishop
sealfin: Is this really safe if I have other classes derived from Base, but not from Derived? I.e:
Base
|
--------------
| |
Derived AnotherSibling
I tried building such a test case, and it compiled, but I'm really not comfortable with this.
For example; if I decided to make another protected function in Base, and this one virtual, when doing the above trick the Derived function would run, even if the original pointer was from another branch of the class tree.
Even so, you solution is probably the best one yet.
Base
|
--------------
| |
Derived AnotherSibling
I tried building such a test case, and it compiled, but I'm really not comfortable with this.
For example; if I decided to make another protected function in Base, and this one virtual, when doing the above trick the Derived function would run, even if the original pointer was from another branch of the class tree.
Even so, you solution is probably the best one yet.
Crap. My intricate and detailed ASCII art wasn't reproduced faithfully. Curse you, non whitespace-preserving semantics of HTML!
Anyway, here it is all wrapped in [ code ] tags:
Anyway, here it is all wrapped in [ code ] tags:
Code:
Base
|
-----------
| |
Derived AnotherSibling
Lemme try an explaination...
This will work:
Because I'm allowed to call protected and public members of my base class.
This will work:
For pretty much the same reasons.
And as we know, (the curious case)... this does NOT work:
Why?
Because the compiler knows this is some kind of "Spatial", BUT it could be some OTHER derived class of "Spatial".
It's a little bit of splitting hairs, but I believe its done that way because if I inherit from "Spatial" to create a class "Foo" and I see something that is "protected", I expect that only "Spatial" or "Foo" will ever call that protected method on instances of "Foo". This way I can assume things about the state of my "Foo" objects. I don't want some "Node" object being able to touch my protected stuff (unless its through public Spatial stuff I already know about).
Clear as mud?
This will work:
Code:
void Node::addChild(Spatial* child)
{
set_parent(this);
}This will work:
Code:
void Node::addChild(Spatial* child)
{
Node * node = (Node *) child;
node->set_parent(this);
}And as we know, (the curious case)... this does NOT work:
Code:
void Node::addChild(Spatial* child)
{
child->set_parent(this);
}Why?
Because the compiler knows this is some kind of "Spatial", BUT it could be some OTHER derived class of "Spatial".
It's a little bit of splitting hairs, but I believe its done that way because if I inherit from "Spatial" to create a class "Foo" and I see something that is "protected", I expect that only "Spatial" or "Foo" will ever call that protected method on instances of "Foo". This way I can assume things about the state of my "Foo" objects. I don't want some "Node" object being able to touch my protected stuff (unless its through public Spatial stuff I already know about).
Clear as mud?
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| On visibility culling and 2d physics engines | TomorrowPlusX | 1 | 4,761 |
Mar 16, 2011 07:47 AM Last Post: Skorche |
|

