3

I have some troubles understanding how to manage the access rights of virtual methods. I made two small code samples, but I can't understand how things work.

Code Sample 1

The first code contains 3 classes: a mother class Foo and two derived classes. The class Baz looks a little bit like a Composite. There's a virtual method, but it's protected.

class Foo
{
protected:
    virtual void doIt() = 0;
};

class Bar : public Foo
{
protected:
    void doIt()
    {}
};

class Baz : public Foo
{
protected:
    void doIt()
    {
        M_foo->doIt(); // Error here
    }
private:
    Foo* M_foo;
};

When trying to compile (Visual C++ 2010) this, I get an error: I can't call doIt from a pointer to Foo in the derived class. So, my understanding was "I can't call this method because it could actually call another one (e.g. the one of Bar) to which I have no right".

Code Sample 2

I decided to change a bit the design of the code and design a function instead of the virtual method. However, to access a protected method, I need to add friendship with my function.

class Foo
{
    friend void doItPlease( Foo* foo);

protected:
    virtual Foo* getChild() = 0;
};

class Bar : public Foo
{
protected:
    Foo* getChild()
    { return 0;}
};

class Baz : public Foo
{
protected:
    Foo* getChild()
    {
        return M_foo;
    }
private:
    Foo* M_foo;
};

void doItPlease( Foo* foo)
{
    Foo* myFoo( foo->getChild() );
};

This code compiles fine. The problem is that I can't understand why: I have declared only the base class as friend, not the children classes and friendship is not inherited. But now, when I call getChild from the function, it is like I would call a method to which I have no right (the one in Baz e.g.).

Could someone explain me how are the rights related to virtual methods managed?

4

3 回答 3

2

Those are the rules for protected. They allow access to the base class subobject, but not for any unrelated instances like yours.

If you google for protected, you will find advice to avoid it in the first place, use private and public only, the intermediate is quite rarely good.

The point is that you define privateness from base class' perspective. If some action is allowed from the outside, it's irrelevant that the unknown party is freestanding or happens to be a subclass. The only relevant attribute is it's being known to be trusted or not.

If the particular derived class is defined along with base, feel free to make it friend, just keep maintaining the rules.

于 2013-06-07T12:26:53.750 回答
1
class Foo
{
public:
    friend class Baz;
protected:
    virtual void doIt() = 0;
};


class Baz : public Foo
{
public:
    Baz(Foo* foo)
        : M_foo(foo)
    {
    }

protected:
    void doIt()
    {
        M_foo->doIt();
    }
private:
    Foo* M_foo;
};
于 2013-06-07T12:19:17.767 回答
0

This could not work beacause Foo::doIt is an undifined virtual method method

class Baz : public Foo
{
protected:
    void doIt()
    {
        Foo::doIt();
    }
};

But if you have something like this it's should work fine

class Baz : public Foo
{
    Baz() 
    {
         M_foo = new Bar();
    }
protected:
    void doIt()
    {
        M_foo->doIt();
    }
private:
    Foo* M_foo;
};
于 2013-06-07T12:26:17.683 回答