Наследование вложенного класса и области видимости

Рассмотрим следующий код:

namespace base {
class Base {
protected:
class Nested {
protected:
Base* base;

public:
Nested(Base* _base) : base( _base ){}

virtual void test() {
base->foo();
/*
* hmm.. we can use protected methods
*/
base->bar();
}
};

protected:
Nested* nested;

void bar(){}

public:
void foo(){}

virtual void test() {
nested = new Nested(this);
nested->test();
}
};
};

namespace inherited {
class Base : public base::Base {
public:
Base()
: base::Base() {}

protected:
class Nested : public base::Base::Nested {
public:
Nested( inherited::Base* base )
: base::Base::Nested( base ) {}

public:
virtual void test() {
base->foo();
/*
* hmm.. and now they are not accessible
*/
// base->bar();
}
};

public:
virtual void test() {
foo();
bar();

nested = new Nested(this);
nested->test();
}
};
};

Мои вопросы, почему у нас есть доступ к защищенным методам / свойствам base::Base от base::Base::Nested но нет доступа к тем же методам / свойствам inherited::Base от inherited::Base::Nested?

Единственное, что я мог предположить, это то, что base::Base это своего рода глобальный охват за base::Base::Nested таким образом они доступны. inherited::Base это своего рода глобальный охват за inherited::Base::Nested и защищенные члены base::Base не доступны. Однако публичное наследование не должно изменять область видимости, и причина невозможности доступа для меня неясна.

2

Решение

Кажется, проблема заключается в типе хранимого указателя, а не в правах доступа. Учти это:

class B {
protected:
void bar();
};

class D : public B {
public:
void call() {
this->bar(); // works
static_cast<B*>(this)->bar(); // does not work
}
};

Ситуация похожа, когда вы пытаетесь позвонить bar сквозь
указатель, который хранится в базе.

Вы можете обойти эту проблему, опустив базу, но я бы категорически против этого.

2

Другие решения

В §11.4 / 1 говорится о доступе к защищенным членам (выделение мной соответствующих частей):

Дополнительная проверка доступа, помимо описанной ранее в разделе 11, применяется, когда нестатический элемент данных или функция нестатического члена является защищенным членом своего класса именования (11.2). Как описано ранее, доступ к защищенному члену предоставляется, потому что ссылка происходит у друга или члена некоторого класса C. Если доступ должен формировать указатель на член (5.3.1), спецификатор вложенного имени должен обозначать C или класс, производный от C. Все другие обращения включают (возможно, неявное) выражение объекта (5.2.5). В этом случае классом выражения объекта должен быть C или класс, производный от C.

Это нелегко интерпретировать. К счастью, в Стандарте приведено несколько примеров, иллюстрирующих значение, и один из них, похоже, является именно вашим случаем (если я не понял что-то в вашем коде, что вполне возможно):

(Обратите внимание, что я удалил ненужные части примеров и переименовал некоторые элементы для простоты.)

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

class D : public B {
void mem(B*);
};void D::mem(B* pb) {
pb->i = 1;                // ill-formed
i = 3;                    // OK (access through this)

/* The following cases are not directly relevant: */
B::i = 4;                 // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i;   // ill-formed
int B::* pmi_B2 = &D::i;  // OK
j = 5;                    // OK (because j refers to a static member)
B::j = 6;                 // OK (because B::j refers to a static member)
}

Другими словами, в

pb->i = 1;

член i найден через pbуказатель на базовый класс, следовательно, класс именования является B, Но доступ происходит из mem(), который является членом D, B не идентичен Dи не вытекает из этого (хотя D происходит от B), поэтому доступ запрещен.

Но в

i = 3

член найден через thisследовательно, класс именования D и доступ разрешен.

1

По вопросам рекламы [email protected]