1

I always thought I know what protected means. There is also a good explanation here: Private and Protected Members : C++. I understand it as: whenever I am in a context of a derived class, I can call protected members of its base.

In the following code I am trying to call a protected method in a derived class, but it is called on another object which is in a different branch of inheritance. This, for some reason, causes an error (tried both in g++ and clang++).

#include <iostream>

class A {
    protected:
        void foo() {
            std::cout << "Hello world!\n";
        }
};

class B : public A {
};

class C : public A {
    public:
        void bar(B* other) {
            foo(); //OK
            other->foo(); //Error
        }
};

int main() {
    return 0;
}

So my question is: what exactly are the rules for the protected members? Did it change recently with the new C++ standards?

Community
  • 1
  • 1
CygnusX1
  • 20,968
  • 5
  • 65
  • 109
  • "what _exactly_ are the rules for the protected members?" If you want the exact rules then read the standard. "Did it change recently with the new C++ standards?" No. – Jonathan Wakely Mar 18 '14 at 15:35

1 Answers1

-1

Everyone needs a friend!

Classes are no different: when they need to share big or small secrets (private or protected) then they need to know they have a friend. Simply addin a line to your A class stating that C is a friend will allow access to the otherwise inaccessible members and functions:

friend class C;

Immediately after the last } of the foo() function will allow C access.

This link at cplusplus.com will help with more detail about friend classes, although, in most cases a rethink of the inheritance hierarchy may be in order if you find yourself having to grant friend status too often.

here is a modified version of your source with friends:

#include <iostream>

class A {
    protected:
        void foo() {
            std::cout << "Hello world!\n";
        }
        friend class C;
};

class B : public A {
};

class C : public A {
    public:
        void bar(B* other) {
            foo(); //OK
            other->foo(); //no error if A and C are friends
        }
};

int main() {
    B* b = new B();
    C* c = new C();
    c->bar(b);
    return 0;
}

Let me know if you need more info:)

Addendum: The error occurs because you have a layer of indirection and whilst B or C can access a protected method from their immediate ancestor A, they cannot access it via an instance of the other class, because at that level the protected member is to all intents and purposes private:

Class A    ---    protected foo()
Class B    ---    inherits from A: foo() effectively private at B level
Class C    ---    inherits from A: foo() effectively private at C level
           ---    bar() method calls instance of B to provide access to foo() via B
                  however this is not valid because foo() is private for B, 
                  therefore C cannot call it
           ---    also has its own call to foo(): Valid call to its own private function

Hopefully this makes a bit more sense of the way that the visibility works at the different levels, I will look up some references once I get home tonight and have access to my books.

GMasucci
  • 2,834
  • 22
  • 42
  • 'friend' is an override for privacy and I am well aware of that solution, but it does not answer the question at all - why the error occurs. – CygnusX1 Mar 19 '14 at 06:57
  • @CygnusX1 I have updated the answer to include the rationale of why `b->foo()` is not available from an instance of class C. – GMasucci Mar 19 '14 at 10:18
  • The "effectively private" is totally unclear if not wrong. If you have inheritance `A->B->C->D` you can still access protected methods of A in D. Read the answer in the duplicate - they answer the problem well, although the wording is not clear at first. – CygnusX1 Mar 19 '14 at 10:29
  • I agree with you, however the inheritance in this instance is A->B then A->C; B is a sibling to C therefore the protected members of B are effectively private as far as C is concerned and vice versa. If C were a child of B then there would be no problem, it is simply they are on different branches of the inheritance tree: Child classes maintain visibility of protected members, however siblings do not. (yes I know I am mixing linguistic private and C++ `private` however I could think of no more concise a way to express it. I shall rethink and repost:) see if I can make this more concise. – GMasucci Mar 20 '14 at 16:20