12

Consider the following example

class base
{
protected :
    int x = 5;
    int(base::*g);
};
class derived :public base
{
    void declare_value();
    derived();
};
void derived:: declare_value()
{
    g = &base::x;
}
derived::derived()
    :base()
{}

As per knowledge only friends and derived classes of the base class can access the protected members of the base class but in the above example I get the following error "Error C2248 'base::x': cannot access protected member declared in class " but when I add the following line

friend class derived;

declaring it as friend , I can access the members of the base class , did I do some basic mistake in the declaring the derived class ?

8
  • Well, the constructor of derived is private, so the class will be tricky to use, but I don't think that's the problem. Why not try it using a simpler access? For example, a derived class function that just returns x (Hint: you won't need to specify base:: to access it) Commented Aug 13, 2018 at 14:28
  • Does stackoverflow.com/questions/477829/… answer your question? It's very similar. Commented Aug 13, 2018 at 14:30
  • 3
    why to not use just : g = &x; ?
    – Simion
    Commented Aug 13, 2018 at 14:30
  • @SebastianRedl the question you link is about calling a protected method on another instance, which isnt exactly the case here Commented Aug 13, 2018 at 14:32
  • @user463035818 The reasoning is the same though. You try to access a protected member through an access path that is not your class. Which is why songyuanyao's answer works. Commented Aug 13, 2018 at 14:36

2 Answers 2

13

The derived class could access the protected members of base class only through the context of the derived class. On the other word, the derived class can't access protected members through the base class.

When a pointer to a protected member is formed, it must use a derived class in its declaration:

struct Base {
 protected:
    int i;
};

struct Derived : Base {
    void f()
    {
//      int Base::* ptr = &Base::i;    // error: must name using Derived
        int Base::* ptr = &Derived::i; // okay
    }
};

You can change

g = &base::x;

to

g = &derived::x;
6
  • @user463035818 g = &x;? No. &x is with type int*, which can't be assigned to pointer to member. LIVE Commented Aug 13, 2018 at 14:55
  • 1
    The reason for this is that a derived class is only allowed to access the base protected members for its own type. Imagine a Shape base class with protected members. If Square inherits from it, we would not want Square to access the protected members of a Circle. (Point being, just because X inherits from Base doesn't mean X should have access to all Base protected members, only from those that are actually in use by objects of type X.) The base::qualification no longer is in the context of a derived class, and so the protected access prevents it. Commented Aug 13, 2018 at 14:57
  • there seems to be a difference between &(foo::x) and &foo::x i wasnt aware of (first is a int*, second is a pointer to int member) Commented Aug 13, 2018 at 15:03
  • @user463035818 Yes. For this case &(derived::x) is same as &(x) and &x. Commented Aug 13, 2018 at 15:09
  • 1
    @Rick Protected allows access to members (and friends) of the class that declares it, and also to its derived classes. What is NOT allowed is if X is a base with a protected member, and two classes A and B both derive from X. A can see protected member of X only when looking at classes of type A (since it is its own data), but not X's protected members in class B, and vice versa. Given a pointer to base, you don't know if it actually points to A or B, and so to disallow A from seeing B's protected data (and vice versa) it's just not allowed. Commented Apr 23, 2020 at 15:32
0

My compiler actually said I needed to add a non-default constructor to base because the field is not initialized.

After I added

base() : g(&base::x) {}

it did compile without problems.

2
  • 2
    That's working because you are accessing base::x from inside base, which obviously will have access. Commented Aug 13, 2018 at 14:55
  • @ChrisUzdavinis I did not remove any lines, the line that is giving the error in the question is still there and happily compiling without errors. I just fixed the other errors by adding a constructor.
    – nvoigt
    Commented Aug 13, 2018 at 14:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.