У меня есть следующий код:
struct A {
protected:
A() {}
A* a;
};
struct B : A {
protected:
B() { b.a = &b; }
A b;
};
Это странно не компилируется. Виновником является b.a = &b;
назначение: и GCC, и Clang жалуются, что A()
защищен, что не должно быть проблемой, потому что B наследует A. В какой темный угол стандарта я вступил?
Значение protected
является то, что производный тип будет иметь доступ к этому члену своя база а не какого-либо случайного объекта*. В вашем случае вы пытаетесь изменить b
член, который находится вне вашего контроля (то есть вы можете установить this->a
, но нет b.a
)
Существует хак, чтобы заставить это работать, если вы заинтересованы, но лучшим решением будет рефакторинг кода, а не зависеть от взломов. Вы могли бы, например, предоставить конструктор в A
это занимает A*
в качестве аргумента (этот конструктор должен быть открытым), а затем инициализировать его в списке инициализатора B
:
A::A( A* p ) : a(p) {}
B::B() : b(&b) {}
* protected
предоставляет вам доступ к базовому члену в любом случае вашего собственного типа или производного от вашего собственного типа.
Здесь на самом деле есть две отдельные проблемы.
Во-первых, строка не просто выполняет присваивание, но пытается инициализировать базовый класс (который работает нормально) и член b
, Чтобы создать b
член должен построить его, и как член это нужно public
доступ к конструктору, которого у него нет.
Тогда назначение также не может получить доступ к непубличному участнику b
потому что, опять же, это не тип B
но типа A
вместо.
Помни что protected
означает, что вы можете получить доступ к частям A
через B
только объект (или ребенок).
В этом случае сообщите нам свою реальную проблему, и мы постараемся помочь решить ее. Наследование и составление от одного типа — это дизайнерский запах.
Все компиляторы, которые я тестировал, жаловались на несколько вещей, и, в частности, защищенный конструктор был бы проблемой, даже если оператор присваивания был удален.
Вы не можете получить доступ к protected
члены любого экземпляра типа, который вы производите. Эта проблема проясняется в примерах 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
// ...
}
Это кажется большим ограничением языка C ++. Как бы вы решили проблему следующим образом:
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);
}
};
В этом примере я не хочу делать метод SaveState
видимый снаружи Node
иерархия. Единственный метод Save
должно быть public
,