“Друзі” класу. Дружні класи та дружні функції. Ключове слово friend. Приклади
Зміст
- 1. Для чого використовуються так звані “друзі” класу?
- 2. Яка загальна форма оголошення “дружнього” класу? Ключове слово friend
- 3. Яка загальна форма оголошення “дружньої” функції до деякого класу?
- 4. В якому місці (розділі) оголошення класу можна оголошувати дружній клас або функцію?
- 5. Скільки “дружніх” функцій та “дружніх” класів можна оголошувати у тілі класу?
- 6. Як отримати об’єкт потрібного класу у “дружній” функції, щоб мати доступ до усіх його членів? Приклад
- 7. Приклад оголошення класу, що є дружнім до іншого класу
- 8. Приклад оголошення функції, що є дружньою до іншого класу
- 9. Особливості застосування “дружніх” функцій
- Зв’язані теми
Пошук на інших ресурсах:
1. Для чого використовуються так звані “друзі” класу?
Бувають випадки, коли для заданого класу потрібно оголосити інший клас або функцію, які повинні мати необмежений доступ до внутрішніх змінних та методів класу. Така необхідність виникає з суті задачі, що розв’язується.
Якщо клас A оголошується “дружнім” до класу B, то об’єкти класу A мають доступ до усіх членів даних і методів класу B. Якщо функція оголошується “дружньою” до деякого класу, то у цій функції також є необмежений доступ до членів даних та методів цього класу.
2. Яка загальна форма оголошення “дружнього” класу? Ключове слово friend
Щоб оголосити “дружній” клас до даного класу, використовується ключове слово friend. Загальна форма оголошення “дружнього” класу до даного має вигляд:
class CClass { // ... friend class CFriendClass; // ... }; class CFriendClass { // ... };
де
- CClass – клас, в якому оголошується “дружній” клас CFriendClass. Усі змінні (навіть і private) та методи цього класу є доступними для об’єктів класу CFriendClass;
- CFriendClass – клас, який є “дружнім” до класу CClass. Оголошення “дружнього” класу CFriendClass до класу CClass може бути в будь-якому місці тіла класу – у межах оголошення класу (між фігурними дужками { }).
3. Яка загальна форма оголошення “дружньої” функції до деякого класу?
Оголошення “дружньої” функції до класу починається з ключового слова friend. Загальна форма оголошення “дружньої” функції до класу має вигляд:
friend type FunName(parameters);
де
- FunName – ім’я “дружньої” функції;
- type – тип, що повертається функцією FunName();
- parameters – параметри “дружньої” функції. Щоб отримати об’єкт потрібного класу у функції FunName() доцільно передати у цю функцію посилання (або покажчик) на об’єкт цього класу.
Якщо потрібно оголосити “дружню” функцію у деякому класі, то загальний вигляд такого оголошення наступний:
class CClass { // ... friend type FunName(parameters); // ... };
де
- FunName – ім’я “дружньої” функції;
- type – тип, що повертається функцією FunName();
- parameters – параметри “дружньої” функції.
4. В якому місці (розділі) оголошення класу можна оголошувати дружній клас або функцію?
Оголошувати “дружній” клас або функцію до заданого класу можна у будь-якому місці чи розділі класу в межах його оголошення (між фігурними дужками { } ).
5. Скільки “дружніх” функцій та “дружніх” класів можна оголошувати у тілі класу?
Скільки завгодно.
6. Як отримати об’єкт потрібного класу у “дружній” функції, щоб мати доступ до усіх його членів? Приклад
Щоб отримати об’єкт потрібного класу у функції доцільно передати у цю функцію посилання (або покажчик) на об’єкт цього класу.
Наприклад.
Нехай задано клас з іменем CMyClass. Потрібно оголосити “дружню” функцію до цього класу, яка має ім’я FriendFun(). Функція повертає параметр типу int.
Оголошення класу CMyClass та “дружньої” функції у класі має вигляд:
// оголошення класу CMyClass, в якому є "дружня" функція FriendFun() class CMyClass { // тіло класу // ... friend int FriendFun(CMyClass &); // ... };
Реалізація “дружньої” функції FriendFun():
int FriendFun(CMyClass & mc) { // використання об'єкту класу mc для доступу до членів класу CMyClass // ... };
7. Приклад оголошення класу, що є дружнім до іншого класу
Нехай задано клас Number, що містить цілочисельну величину. Також задано клас RangeNum, який містить величину Number але в межах заданого діапазону.
Щоб з класу RangeNum можна було мати доступ до приватної змінної num класу Number, клас RangeNum оголошується “дружнім” до класу Number.
Лістинг класів Number та RangeNum має вигляд:
// клас, що реалізує ціле число class Number { // оголошення дружнього класу RangeNum до класу Number friend class RangeNum; int num; public: // конструктори Number() { num = 0; } Number(int num) { this->num = num; } }; // оголошення класу RangeNum, який тримає число Number в заданих межах class RangeNum { Number num; // об'єкт класу Number - просте ціле число int min; // нижня межа числа num int max; // верхня межа числа num public: // конструктор класу RangeNum() { // доступ до private-члена класу Number, тому що RangeNum є дружнім до Number num.num = 0; // встановлення діапазону 0..99 за замовчуванням min = 0; max = 99; } // методи доступу int GetNum(void) { return num.num; // доступ до приватного члена з "дружнього" класу Range } void SetNum(int nnum) { num.num = nnum; // доступ до приватного члена з "дружнього" класу Range if (num.num>max) num.num = max-1; if (num.num<min) num.num = min; } // встановлення діапазону для num в заданих межах void SetRange(int min, int max) { this->min = min; this->max = max; if (num.num>max) num.num = max-1; // знову доступ через дружній клас if (num.num<min) num.num = min; } };
Використання класів у іншому програмному коді
int _tmain(int argc, _TCHAR* argv[]) { // об'єкт класу Range RangeNum r; int d; d = r.GetNum(); // d = 0 r.SetRange(100, 200); r.SetNum(101); d = r.GetNum(); // d = 101 r.SetRange(10, 20); // корегується значення num d = r.GetNum(); // d = 19 r.SetNum(-10); d = r.GetNum(); // d = 10 return 0; }
Якщо у класі Number в оголошенні “дружнього” класу RangeNum
friend class RangeNum;
забрати ключове слово friend, то у конструкторі та усіх методах класу при доступі до num.num компілятор видасть помилку:
Number::num: cannot access private member declared in class 'Number'
8. Приклад оголошення функції, що є дружньою до іншого класу
У прикладі оголошується клас Radius, що містить величину радіуса деякої геометричної фігури. У класі оголошуються:
- одна прихована (private) змінна radius;
- методи Get() та Set() для доступу до змінної radius;
- дві зовнішні “дружні” функції GetLength() та GetArea();
- один “дружній” клас Volume. У класі Volume оголошується зовнішній (public) метод GetVolume(), який повертає об’єм кулі заданого радіуса.
Лістинг додатку типу “Win32 Console Application” наступний:
#include "stdafx.h" #include <iostream> using namespace std; // клас, що реалізує величину радіуса геометричної фігури class Radius { private: double radius; // прихована змінна radius // оголошення "дружніх" функцій - в будь-якому розділі класу Radius friend double GetLength(Radius &); friend double GetArea(Radius &); // оголошення "дружнього" класу friend class Volume; public: // методи доступу до radius double Get(void) { return radius; } void Set(double nradius) { radius = nradius; } }; // "дружні" функції до класу Radius // довжина кола double GetLength(Radius & r) { // доступ до private-члена radius класу з "дружньої" функції GetLength() return (double)(2 * r.radius * 3.1415); } // площа круга double GetArea(Radius & r) { // доступ до private-члена radius класу з "дружньої" функції GetArea() return (double)(r.radius * r.radius * 3.1415); } // оголошення "дружнього" класу class Volume { public: // клас містить тільки одну функцію Volume double GetVolume(Radius * r) // функція отримує покажчик на Radius { // доступ до private-члена класу Radius з "дружнього" класу Volume return (double)(4.0 / 3.0 * 3.1415 * r->radius * r->radius * r->radius); } }; int _tmain(int argc, _TCHAR* argv[]) { // об'єкт класу Radius Radius r; Volume v; double len, area, vol; r.Set(3); // виклик зовнішньої "дружньої" функції GetLength() len = GetLength(r); // передача об'єкту класу Radius за посиланням // виклик зовнішньої "дружньої" функції GetArea() area = ::GetArea(r); // передача за посиланням // виклик функції "дружнього" класу v vol = v.GetVolume(&r); // передача за покажчиком cout << "Length = " << len << endl; // Length = 9.4245 cout << "Area = " << area << endl; // Area = 28.2735 cout << "Volume = " << vol << endl; // Volume = 113.094 return 0; }
Як видно з вищенаведеного коду, “дружні” функції отримують вхідним параметром посилання або покажчик на об’єкт класу, до членів даних та методів якого вони мають необмежений доступ.
9. Особливості застосування “дружніх” функцій
Про “дружні” функції можна сказати наступне:
- “дружня” функція не отримує покажчик this класу в якому вона реалізована
- об’єкти класів передаються в “дружню” функцію явно через параметри
- “дружні” функції не викликаються через об’єкт класу, друзями якого вони є
- на “дружні” функції не діють специфікатори доступу private, protected, public
- “дружня” функція не є компонентою того класу до якого вона “дружня”
- “дружня” функція може бути “дружньою” по відношенню до декількох класів
Зв’язані теми
- Поняття класу. Оголошення класу. Об’єкт класу. Класи в середовищі CLR. Інкапсуляція даних в класі
- Види функцій-членів класу. Звичайні функції-члени класу. Статичні (static) функції-члени класу. Приклади використання