Дружественные функции

   
На этом шаге мы начнем изучение дружественных функций и их возможностей.

   
Дружественной функцией класса называется функция, которая, не являясь
его компонентом, имеет доступ к его защищенным и собственным компонентам.
Функция не может стать другом класса "без его согласия". Для получения прав друга
функция должна быть описана в теле класса со спецификатором friend. Именно при
наличии такого описания класс предоставляет функции права доступа к защищенным и
собственным компонентам. Пример класса с дружественной функцией:

//OOР13_01.СРР - класс с дружественной функцией.
#include <conio.h>   // Для консольных функций в текстовом режиме.
// Класс - "символ в заданной позиции экрана": 
class charlocus {    
	int x, y;   // Координаты знакоместа на экране дисплея.
	// Значение символа, связанного со знакоместом:
	char cc;
	// Прототип дружественной функции для замены символа:
	friend void friend_put(charlocus *, char);
  public:
	charlocus(int xi, int yi, char ci) // Конструктор.
		{ x = xi; y = yi; cc = ci; }
	void display (void)  // Вывести символ на экран.
		{ gotoxy(x,y); putch(cc); }
};
// Дружественная функция замены символа в конкретном
// объекте:
void friend_put(charlocus *p, char c)
  { p->cc = c; }
void main (void)
{ charlocus D(20,4,'d');  // Создать объект.
  charlocus S(10,10,'s'); // Создать объект.
  D.display (); getch();
  S.display (); getch();
  friend_put(&D,'*'); D.display(); getch();
  friend_put(&S,'#'); S.display(); getch();
}

Текст этой программы можно взять здесь.

   
Программа последовательно выводит на экран d (в позицию 20, 4), s (в позицию 10, 10),
* (в позицию 20, 4), # (в позицию 10, 10).

   
Для работы с экраном в текстовом режиме использованы две функции из библиотеки Turbo С. Их
прототипы находятся в заголовочном файле conio.h, где специфицированы так называемые
"консольные" функции ввода-вывода. В других компиляторах языка C++ эти функции могут
быть определены иначе.

  • void gotoxy (int х, int у) - позволяет поместить курсор в позицию экрана с
    "координатами" х (по горизонтали) и у (по вертикали). В обычном (текстовом) режиме количество
    строк 25 (у меняется от 0 до 24), количество столбцов 80 (х меняется от 0 до 79). Позиция
    с координатами (0,0) соответствует левому верхнему углу экрана.
  • void putch (int s) - выводит на экран в местоположение курсора изображение символа,
    код которого определяется значением параметра s.
  • int getch(void) - также относится к библиотечным консольным функциям. Ее основное назначение -
    чтение кода из буфера клавиатуры без вывода соответствующего символа на экран. При
    вызове этой функции программа останавливает выполнение и ожидает сигнала от клавиатуры.
    Тем самым у пользователя появляется возможность проследить смену изображений на экране.

   
Прокомментируем приведенную программу.

   
Функция friend_put() описана в классе charlocus как дружественная и определена
как обычная глобальная функция (вне класса, без указания его имени, без операции :: и без
спецификатора friend). Как дружественная она получает доступ к собственным данным
класса и изменяет значение символа того объекта, адрес которого будет передан ей как
значение первого параметра.

   
Выполнение основной программы очевидно. Создаются два объекта D и S, для
которых определяются координаты мест на экране и символы (d, s). Затем общедоступная функция
класса charlocus::display() выводит символы в указанные позиции экрана. Функция friend_put заменяет
символы объектов, что демонстрирует повторный вывод на экран.

   
Отметим особенности дружественных функций.

  • Дружественная функция при вызове не получает указателя this. Объекты классов должны
    передаваться дружественной функции только явно через аппарат параметров.
  • При вызове дружественной функции нельзя использовать операции выбора:
        имя_объекта.имя_функции
                 и
        указатель_на_объект  -> имя_функции
    

    Все это связано с тем фактом, что дружественная функция не является компонентом класса.

  • Именно поэтому на дружественную функцию не распространяется и действие спецификаторов доступа
    (public, protected, private). Место размещения прототипа дружественной функции внутри
    определения класса безразлично. Права доступа дружественной функции не изменяются и
    не зависят от спецификаторов доступа. В приведенном примере описание функции
    friend_put() помещено в разделе, который по умолчанию имеет статус доступа private.
  •    
    Итак, дружественная функция:

    • не может быть компонентной функцией того класса, по отношению к которому определяется как
      дружественная;
    • может быть глобальной функцией:
          class CL { friend int f1 (...); ... }; 
          int f1(...) { тело_функции }
      
    • может быть компонентной функцией другого ранее определенного класса:
           class CLASS { ...  char f2(...); ... };
           class CL    { ...  friend char CLASS::f2(...); ... };
      

         
      В примере класс CLASS с помощью своей компонентной функции f2() получает
      доступ к компонентам класса CL. Компонентная функция некоторого класса (CLASS) может
      быть объявлена дружественной функцией другому классу (CL), если только определение этого
      первого класса размещено раньше, чем определение второго.

    • может быть дружественной по отношению к нескольким классам:
      // Предварительное  неполное определение класса. 
      class  CL2;
      class CL1 { friend void ff(CL1,CL2); ... }; 
      class CL2 { friend void ff(CL1,CL2); ... }; 
      void ff(CL1 cl, CL2 c2) { тело_функции }
      

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



    Вы можете оставить комментарий, или Трекбэк с вашего сайта.

    Оставить комментарий