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