Cannot access protected member of base class in de

2019-02-16 08:11发布

问题:

I have the following code:

struct A {
protected:
    A() {}

    A* a;
};

struct B : A {
protected:
    B() { b.a = &b; }

    A b;
};

It strangely doesn't compile. The culprit is the b.a = &b; assignment: both GCC and clang complain that A() is protected, which shouldn't be a problem because B inherits A. Which dark corner of the standard have I come into?

回答1:

The meaning of protected is that the derived type will have access to that member of its own base and not of any random object*. In your case, you care trying to modify b's member which is outside of your control (i.e. you can set this->a, but not b.a)

There is a hack to get this to work if you are interested, but a better solution would be to refactor the code and not depend on hacks. You could, for example, provide a constructor in A that takes an A* as argument (this constructor should be public) and then initialize it in the initializer list of B:

A::A( A* p ) : a(p) {}
B::B() : b(&b) {}

* protected grants you access to the base member in any instance of your own type or derived from your own type.



回答2:

There are actually two separate problems here.

The first is that the line doesn't just do an assignment, but tries to initialize the base class (which works fine) and the member b. To create the b member it needs to construct it, and as a member it needs public access to a constructor, which it doesn't have.

Then the assignment also is unable to access non-public member of b because again, it's not of type B but type A instead.

Remember that protected means you can access parts of A through a B object (or child) only.

In this case tell us your real problem and we can try to help solve it. Inheriting and composing from the same type is a design smell.



回答3:

All the compilers that I tested complained about several things, and specifically the protected constructor would be a problem even if the assignment statement were removed.

You don't get to access the protected members of any instance of a type you derive from. This issue is clarified in the examples of 11.4p1.

class B {
protected:
  int i;
  static int j;
};

class D1 : public B {
};

class D2 : public B {
  void mem(B*, D1*);
};

void D2::mem(B* pb, D1* p1) {
  pb->i = 1; // ill-formed
  p1->i = 2; // ill-formed
  // ...
}


回答4:

It seems like a big limitation of the C++ language. How would you solve problem like this:

class Node
{
public:
 void Save();
protected:
 virtual void SaveState(int type) = 0;
};

class BinaryNode : public Node
{
protected:
 Node *left;
 Node *right;

 virtual void SaveState(int type) override
 {
    left->SaveState(type);
    right->SaveState(type);
 }
};

In this example I do not want to make method SaveState visible outside Node hierarchy. Only method Save should be public.