Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию
    главная     хостинг    
Поиск по сайту:  
Смотрите также
Языки программирования
C#
MS Visual C++
Borland C++
C++ Builder
Visual Basic
Quick Basic
Turbo Pascal
Delphi
JavaScript
Java
PHP
Perl
Assembler
AutoLisp
Fortran
Python
1C

Интернет-технологии
HTML
VRML
HTTP
CGI
FTP
Proxy
DNS
протоколы TCP/IP
Apache

Web-дизайн
HTML
Дизайн
VRML
PhotoShop
Cookie
CGI
SSI
CSS
ASP
PHP
Perl

Программирование игр
DirectDraw
DirectSound
Direct3D
OpenGL
3D-графика
Графика под DOS

Алгоритмы
Численные методы
Обработка данных

Сис. программирование
Драйверы

Базы данных
MySQL
SQL

Другое

Хостинг


Друзья
demaker.ru
Реклама

Лучший хостинг. Аренда серверов




helloworld.ru

Друзья класса

Три спецификатора доступа обеспечивают в C++ управление доступом. Эти спецификаторы являются основанием принципа инкапсуляции - одного из трёх основных принципов объектно-ориентированного программирования. Соблюдение правил доступа повышает надёжность программного обеспечения.

Спецификаторы доступа способны обеспечить многоуровневую защиту функций и данных в наследуемых классах. Порождаемые на основе "инкапсулированных" классов объекты способны поддерживать жёсткий интерфейс. Они подобны "чёрным" ящикам с чётко обозначенными входами и выходами. Вместе с тем, следует признать, что система управления доступом, реализованная на основе трёх спецификаторов, не является гибкой. С её помощью может быть реализована защита по принципу "допускать ВСЕХ (члены класса, объявленные в секции public) или не допускать НИКОГО (члены класса, объявленные в секциях protected и private)". В C++ существует возможность организации более гибкой защиты. Здесь можно также объявлять функции, отдельные функции-члены классов и даже классы (в этом случае речь идёт о полном множестве функций-членов класса), которые получают доступ к защищённым и приватным членам данного класса. Что означает реализацию системы управления доступом принципу "не допускать НИКОГО, КРОМЕ". Такие функции и классы называют дружественными функциями и классами. Объявление дружественных классов и функций включается в объявление данного класса вместе со спецификатором объявления friend. Здесь нам потребуется всего одна форма Бэкуса-Наура для того, чтобы дополнить синтаксис объявления.

СпецификаторОбъявления ::= friend
                       ::= *****

Рассмотрим небольшой пример использования дружественных функций и классов, а затем сформулируем основные правила работы с друзьями классов. В программе объявлены два класса, один из которых является другом другого класса и всеобщая дружественная функция.

#include <iostream.h>
class XXX; 
/*
Неполное объявление класса. Оно необходимо для объявления типа
параметра функции-члена для следующего класса.
*/
class MMM
{
 private:
  int m1;
 public:
  MMM(int val);
  void TypeVal(char *ObjectName, XXX& ClassParam);
};
MMM::MMM(int val)
{
 m1 = val;
}
/*
Определение функции-члена TypeVal располагается после объявления
класса XXX. Только тогда транслятор узнаёт о структуре класса, к
которому должна получить доступ функция MMM::TypeVal.
*/
class XXX
{
 friend class YYY;
 friend void MMM::TypeVal(char *ObjectName, XXX& ClassParam);
 friend void TypeVal(XXX& ClassParamX, YYY& ClassParamY);
/*
В классе объявляются три друга данного класса: класс YYY, функция-член
класса MMM, простая функция TypeVal. В класс XXX включаются лишь
объявления дружественных функций и классов. Все определения
располагаются в других местах - там, где им и положено быть - в своих
собственных областях видимости.
*/
 private:
  int x1;
 public:
  XXX(int val);
};
XXX::XXX(int val)
{
 x1 = val;
}
void MMM::TypeVal(char *ObjectName, XXX& ClassParam)
{
 cout << "Значение " << ObjectName << ": " << ClassParam.x1 << endl;
}
/*
Отложенное определение функции-члена MMM::TypeVal.
*/
class YYY
{
 friend void TypeVal(XXX& ClassParamX, YYY& ClassParamY);
 private:
  int y1;
 public:
  YYY(int val);
  void TypeVal(char *ObjectName, XXX& ClassParam);
};
YYY::YYY(int val)
{
 y1 = val;
}
void YYY::TypeVal(char *ObjectName, XXX& ClassParam)
{
 cout << "Значение " << ObjectName << ": " << ClassParam.x1 << endl;
}
void TypeVal(XXX& ClassParamX, YYY& ClassParamY);
void main()
{
 XXX mem1(1);
 XXX mem2(2);
 XXX mem3(3);
 YYY disp1(1);
 YYY disp2(2);
 MMM special(0);
 disp1.TypeVal("mem1", mem1);
 disp2.TypeVal("mem2", mem2);
 disp2.TypeVal("mem3", mem3);
 special.TypeVal("\n mem2 from special spy:", mem2);
 TypeVal(mem1, disp2);
 TypeVal(mem2, disp1);
}
void TypeVal(XXX& ClassParamX, YYY& ClassParamY)
{
 cout << endl;
 cout << "???.x1 == " << ClassParamX.x1 << endl;
 cout << "???.y1 == " << ClassParamY.y1 << endl;
}

В этом примере все функции имеют одинаковые имена. Это не страшно. Это даже полезно, поскольку становится очевидным факт существования разных областей действия имён.

В заключение раздела перечислим основные правила пользования новыми средствами управления доступа - дружественной системой защиты.

  • Друзья класса не являются членами класса. Они должны определяться вне класса, для которого они объявляются друзьями, а об особых отношениях между ними и данным классом свидетельствует лишь специальное объявление(!) со спецификатором объявления friend. Объявления дружественного класса означает, что в дружественном классе доступны все компоненты объявляемого класса.
  • Дружественные данному классу функции не являются членами этого класса. Поэтому они не могут быть вызваны из объекта-представителя класса, для которого была объявлена другом данная функция, при помощи операции доступа к члену класса.
  • Дружественная функция может быть функцией-членом другого ранее объявленного класса. Правда, при этом само определение дружественной функции приходится располагать после объявления класса, другом которого была объявлена данная функция. Это не очень удобно и красиво, но зато работает.
  • Дружественная функция не имеет this указателя для работы с классом, содержащим её объявление в качестве дружественной функции. Дружба - это всего лишь дополнение принципа инкапсуляции и ничего более.
  • Дружественные отношения не наследуются. Дружественные функции не имеют доступа к членам производного класса, чьи базовые классы содержали объявления этих функций. Дети не отвечают за отношения своих родителей.

[ Назад | Оглавление | Далее ]









helloworld.ru © 2001-2021
Все права защищены