«Друзья» класса. «Дружественные» классы и функции. Ключевое слово 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) функции-члены класса. Примеры использования