Подтвердить что ты не робот

Невозможно получить доступ к защищенному члену базового класса в производном классе

У меня есть следующий код:

struct A {
protected:
    A() {}

    A* a;
};

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

    A b;
};

Это странно не компилируется. Преступником является назначение b.a = &b;: как GCC, так и clang жалуются, что A() защищен, что не должно быть проблемой, потому что B наследует A. В какой темный угол стандарта я пришел?

4b9b3361

Ответ 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.