10

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 ?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Novice_Developer
  • 1,432
  • 2
  • 19
  • 33
  • 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) – Tim Randall Aug 13 '18 at 14:28
  • Does https://stackoverflow.com/questions/477829/cannot-call-base-class-protected-functions?rq=1 answer your question? It's very similar. – Sebastian Redl Aug 13 '18 at 14:30
  • 3
    why to not use just : g = &x; ? – Simion Aug 13 '18 at 14:30
  • @SebastianRedl the question you link is about calling a protected method on another instance, which isnt exactly the case here – 463035818_is_not_an_ai Aug 13 '18 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. – Sebastian Redl Aug 13 '18 at 14:36
  • Possible duplicate of [Accessing protected members in a derived class](https://stackoverflow.com/questions/3247671/accessing-protected-members-in-a-derived-class) – rustyx Aug 13 '18 at 14:38
  • @SebastianRedl I get your point, though i dont think it is that obvious that this applies here, thus I wouldnt flag it as exact duplicate – 463035818_is_not_an_ai Aug 13 '18 at 14:46
  • That's why I didn't. – Sebastian Redl Aug 13 '18 at 14:47

2 Answers2

12

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;
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • @user463035818 `g = &x;`? No. `&x` is with type `int*`, which can't be assigned to pointer to member. [LIVE](https://wandbox.org/permlink/8PDA9WaRD8ojOHjw) – songyuanyao Aug 13 '18 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. – Chris Uzdavinis Aug 13 '18 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) – 463035818_is_not_an_ai Aug 13 '18 at 15:03
  • @user463035818 Yes. For this case `&(derived::x)` is same as `&(x)` and `&x`. – songyuanyao Aug 13 '18 at 15:09
  • @ChrisUzdavinis I've been thinking this for a while, about *why a derived class member or friend may access the protected members of the base class **only through** a derived object.* And I don't agree with your example. I think the point is, setting `protected` in a class means user could not have access to it from anywhere **outside the class itself**, even if from derived class. Check this [answer](https://softwareengineering.stackexchange.com/questions/345312/why-is-accessing-virtual-protected-functions-of-a-base-class-not-allowed-through) – Rick Apr 22 '20 at 07:51
  • 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. – Chris Uzdavinis Apr 23 '20 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.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • 2
    That's working because you are accessing base::x from inside base, which obviously will have access. – Chris Uzdavinis Aug 13 '18 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 Aug 13 '18 at 14:56