I have the following code:
struct A {
protected:
A() {}
A* a;
};
struct B : A {
protected:
B() { b.a = &b; }
A b;
};
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.
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.
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
.
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
// ...
}