Inheritage visibility in C++

Apprentice
Posts: 19
Joined: 2005.11
Post: #1
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)

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?
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #2
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. Smile
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #3
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.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
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.
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #5
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?
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #6
Add this:

Code:
friend class TheOtherClass;
...to the body of the class which should be able to call private methods on TheOtherClass.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
DDustin
Unregistered
 
Post: #7
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.
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #8
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.
Quote this message in a reply
Moderator
Posts: 702
Joined: 2002.04
Post: #9
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
--
Student and freelance OS X & iOS developer
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #10
Hmmm. I just tried to compile this code:

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)
Quote this message in a reply
Moderator
Posts: 702
Joined: 2002.04
Post: #11
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
--
Student and freelance OS X & iOS developer
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #12
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.
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2005.11
Post: #13
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:

Code:
Base
         |
    -----------
   |           |
Derived  AnotherSibling
Quote this message in a reply
zKing
Unregistered
 
Post: #14
Lemme try an explaination...

This will work:
Code:
void Node::addChild(Spatial* child)
{
    set_parent(this);
}
Because I'm allowed to call protected and public members of my base class.

This will work:
Code:
void Node::addChild(Spatial* child)
{
    Node * node = (Node *) child;
    node->set_parent(this);
}
For pretty much the same reasons.

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?
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  On visibility culling and 2d physics engines TomorrowPlusX 1 5,609 Mar 16, 2011 07:47 AM
Last Post: Skorche