Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Справочник по С++.doc
Скачиваний:
49
Добавлен:
02.05.2014
Размер:
995.33 Кб
Скачать

R.11.3 Описания доступа

Используя уточненное имя, можно установить доступ к члену базового класса в части public или protected описания производного класса. Это называется описанием доступа. Приведем пример: class B { int a; public: int b, c; int bf(); }; class D : private B { int d; public: B::c; // adjust access to `B::c' int e; int df(); }; int ef(D&); Во внешней функции ef можно использовать только имена c, e, и df. Поскольку функция df член класса D, в ней можно использовать имена b, c, bf, d, e и df, но не a. Функция bf - член класса B и в ней можно использовать члены a, b, c и bf. Описания доступа не следует использовать для ограничения доступа к члену, доступному в базовом классе, также как не следует использовать его для обеспечения доступа к члену, который недоступен в базовом классе, например: class B { public: int a; private: int b; protected: int c; }; class D : private B { public: B::a; // описать `a' как общий член D B::b; // ошибка: попытка расширить доступ, // `b' не может быть общим членом D protected: B::c; // описать `c' как защищенный член D B::a; // ошибка: попытка сузить доступ, // `a' не может быть защищенным членом D }; Описание доступа для имени перегруженной функции устанавливает доступ в базовом классе ко всем функциям с этим именем, например: class X { public: f(); f(int); }; class Y : private X { public: X::f; // makes X::f() and X::f(int) public in Y }; Нельзя в производном классе установить доступ к члену базового класса, если в производном классе определен член с этим же именем, например: class X { public: void f(); }; class Y : private X { public: void f(int); X::f; // ошибка: два описания f };

R.11.4 Друзья

Другом класса называется функция, которая не является членом класса, но в которой можно использовать частные и защищенные члены этого класса. Имя друга не принадлежит области видимости класса, и дружественная функция не вызывается с помощью операций доступа к членам ($$R.5.2.4), если только она не является членом другого класса. Следующий пример показывает различие между членами и друзьями: class X { int a; friend void friend_set(X*, int); public: void member_set(int); }; void friend_set(X* p, int i) { p->a = i; } void X::member_set(int i) { a = i; } void f() { X obj; friend_set(&obj,10); obj.member_set(10); } Если в описании friend использовано имя перегруженной функции или операции, только функция, однозначно определяемая типами формальных параметров, становится другом. Функция-член класса X может быть другом класса Y, например: class Y { friend char* X::foo(int); // ... }; Можно объявить все функции класса X друзьями класса Y с помощью спецификации-сложного-типа ($$R.9.1): class Y { friend class X; // ... }; Описание одного класса как друг другого класса дополнительно подразумевает, что частные и защищенные члены класса, предлагающего дружбу, могут использоваться в классе, получающем ее, например: class X { enum { a=100 }; friend class Y; }; class Y { int v[X::a]; // Y друг класса X }; class Z { int v[X::a]; // ошибка: X::a недоступно }; Если класс или функция, объявленные как друзья, не были описаны, их имена попадают в ту же область видимости, что и имя класса, содержащего описание friend ($$R.9.1). Функция, появившаяся первый раз в описании friend, считается эквивалентной функции, описанной как extern ($$R.3.3, $$r.7.1.1). Если функция-друг определена в описании класса, она считается функцией со спецификацией inline и к ней применимо правило переноса определения функции для функций-членов ($$R.9.3.2). Функция-друг, определенная в описании класса, относится на лексическом уровне к области видимости этого класса. Для функции-друга, определенной вне класса, это не так. На описание friend не влияет указание спецификаций-доступа ($$R.9.2). Понятие дружбы не является ни наследуемым, ни транзитивным. Подтвердим это примером: class A { friend class B; int a; }; class B { friend class C; }; class C { void f(A* p); { p->a++; // ошибка: C не друг класса A, хотя // является другом друга класса A } }; class D : public B { void f(A* p) { p->a++; // ошибка: D не друг класса A, хотя // является производным друга класса A } };