У меня есть следующий код C ++:
class A {
protected:
struct Nested {
int x;
};
};
class B: public A {
friend class C;
};
class C {
void m1() {
B::Nested n; // or A::Nested
}
};
Компилируя этот фрагмент с помощью g ++ 4.4, не имеет значения, использую ли я B :: Nested или A :: Nested в m1. Clang принимает B :: Nested
, но не компилируется, если I A :: Nested
. Это ошибка в g ++ или в clang?
Согласно стандарту, GCC правильный, а Clang неверный. В нем говорится, что в 11.2/4
Член m доступен, когда он назван в классе N, если
- m как член N защищен, и ссылка встречается в члене или друге класса N, или в члене или друг класса P, производного от N, где m как член P является частным или защищенным
Это является предметом этого отчета об ошибке Clang, который не позволяет Clang создавать Qt: /show_bug.cgi?id=6840 . Один парень из Clang говорит
На самом деле, я намеренно еще не внедрил это правило. Это либо ошибка в составлении или ужасная ошибка. Он нейтрализует всю «защищенную» спецификатор, это делает корректность кода зависимой от наличие совершенно не связанных между собой классов, это накладывает большие затраты на реализации, и формально неразрешима при наличии шаблонов.
В C++ друзья нетранзитивны. Друзья твоих друзей не обязательно мои друзья.
Делая Nested защищенным в A, вы указываете, что все подклассы могут использовать этот элемент, но никому другому не разрешено использовать его. Можно считать, что это своего рода друг. A делает всех подклассов друзьями в отношении доступа к вложенной структуре.
Теперь B делает C другом, но это не означает, что C также является другом A. Таким образом, C не должен иметь доступа к Nested.
НО: поведение отличается от C++03. В C++03 вложенный класс является полноправным членом включающего класса и поэтому имеет полные права доступа. Дружба по-прежнему НЕ транзитивна, но теперь членский доступ.
Вы можете посмотреть http://www.rhinocerus.net/forum/language-c-moderated/578874-friend-transitive-nested-classes.html, где объясняется аналогичная проблема. .