Различия
Показаны различия между двумя версиями страницы.
— | druzhestvennye_funkcii_klassy._druzhestvennaja_peregruzka [2021/07/31 21:57] (текущий) – создано - внешнее изменение 127.0.0.1 | ||
---|---|---|---|
Строка 1: | Строка 1: | ||
+ | ====== Дружественные функции ====== | ||
+ | Дружественной функцией класса называется функция, | ||
+ | |||
+ | * **Некоторые особенности дружественных функций.** | ||
+ | - Дружественная функция при вызове не получает указателя this. | ||
+ | - Объекты классов должны передаваться дружественной функции только явно через аппарат параметров. | ||
+ | - Дружественные функции нельзя вызывать через объекты классов, | ||
+ | имя_объекта.имя_функции | ||
+ | указатель_на_объект | ||
+ | - На дружественную функцию не распространяется действие спецификаторов доступа (public, protected, private), поэтому место размещения прототипа дружественной функции внутри определения класса безразлично. | ||
+ | - Дружественная функция не может быть компонентной функцией того класса, | ||
+ | - Дружественная функция может быть дружественной по отношению к нескольким классам. | ||
+ | |||
+ | * **Кое-что о применении** | ||
+ | Использование механизма дружественных функций позволяет упростить интерфейс между классами. Например, | ||
+ | |||
+ | В качестве примера рассмотрим дружественную функцию двух классов " | ||
+ | |||
+ | - Класс " | ||
+ | - Компонентными данными класса " | ||
+ | - Дружественная функция определяет уклонение заданной точки от заданной прямой. Если (a, b) - координаты конкретной точки, то для прямой, | ||
+ | |||
+ | В нижеописанной программе определены классы с общей дружественной функцией, | ||
+ | < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // Предварительное | ||
+ | class line_; | ||
+ | |||
+ | // Класс | ||
+ | class point_ | ||
+ | { | ||
+ | // Координаты точки на плоскости. | ||
+ | float x, y; | ||
+ | public: | ||
+ | // Конструктор. | ||
+ | point_(float xn = 0, float yn = 0) | ||
+ | { | ||
+ | x = xn; | ||
+ | y = yn; | ||
+ | } | ||
+ | friend float uclon(point_, | ||
+ | }; | ||
+ | |||
+ | // Класс " | ||
+ | class line_ | ||
+ | { | ||
+ | // Параметры прямой. | ||
+ | float A, B, C; | ||
+ | public: | ||
+ | // Конструктор. | ||
+ | line_(float a, float b, float c) | ||
+ | { | ||
+ | A = a; | ||
+ | B = b; | ||
+ | C = c; | ||
+ | } | ||
+ | friend float uclon(point_, | ||
+ | }; | ||
+ | // Внешнее определение дружественной функции. | ||
+ | float uclon(point_ p, line_ l) | ||
+ | { | ||
+ | // вычисление отклонения прямой | ||
+ | return l.A * p.x + l.B * p.y + l.C; | ||
+ | } | ||
+ | void main() | ||
+ | { | ||
+ | // Определение точки P. | ||
+ | point_ P(16.0, | ||
+ | |||
+ | // Определение прямой L. | ||
+ | line_ L(10.0, | ||
+ | |||
+ | cout << "\n Result" | ||
+ | } | ||
+ | </ | ||
+ | ====== Дружественная перегрузка ====== | ||
+ | |||
+ | Дружественная перегрузка.Итак, | ||
+ | |||
+ | Проиллюстрируем особенности оформления операции-функции в виде дружественной функции класса. | ||
+ | |||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс реализующий работу | ||
+ | // с логическим значением | ||
+ | class Flag | ||
+ | { | ||
+ | bool flag; | ||
+ | // дружественная функция (перегрузка | ||
+ | // оператора ! - замена значения флага | ||
+ | // на противоположное) | ||
+ | friend Flag& operator !(Flag& | ||
+ | | ||
+ | |||
+ | // Конструктор. | ||
+ | Flag(bool iF) | ||
+ | { | ||
+ | flag = iF; | ||
+ | } | ||
+ | // Компонентная функция показа значения флага | ||
+ | // в текстовом формате: | ||
+ | void display(){ | ||
+ | if(flag) cout<<" | ||
+ | else cout<<" | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Определение дружественной | ||
+ | // операции-функции. | ||
+ | // (this не передается, | ||
+ | Flag& operator !(Flag & f) | ||
+ | { | ||
+ | // | ||
+ | f.flag=!f.flag; | ||
+ | return f; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | Flag A(true); | ||
+ | |||
+ | // показ начального значения | ||
+ | A.display(); | ||
+ | |||
+ | // замена значения на противоположное | ||
+ | // с помощью перегруженного оператора | ||
+ | A=!A; | ||
+ | // показ измененного значения | ||
+ | A.display(); | ||
+ | } | ||
+ | |||
+ | Результат выполнения программы: | ||
+ | |||
+ | TRUE | ||
+ | |||
+ | FALSE | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | Глобальная перегрузка. | ||
+ | В C++ кроме двух известных вам разновидностей перегрузки (перегрузка в классе и дружественная перегрузка), | ||
+ | |||
+ | Допустим, | ||
+ | |||
+ | |||
+ | a+b означает a.operator+(b) | ||
+ | |||
+ | |||
+ | |||
+ | Однако, | ||
+ | |||
+ | |||
+ | C operator+(C, | ||
+ | |||
+ | |||
+ | |||
+ | Такой вариант перегрузки тоже применим к выражению a+b, где a и b передаются соответственно в первом и втором параметрах функции. Из этих двух форм предпочтительной считается перегрузка в классе. Т. к. вторая форма требует открытого обращения к членам класса, | ||
+ | |||
+ | Смешивать эти две формы в программе не рекомендуется. Если для некоторого оператора определены обе формы с одинаковыми типами формальных параметров, | ||
+ | |||
+ | Тем не менее, глобальная перегрузка операторов обеспечивает симметрию, | ||
+ | |||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс " | ||
+ | class Point | ||
+ | { | ||
+ | // координаты точки | ||
+ | int X; | ||
+ | int Y; | ||
+ | | ||
+ | |||
+ | // конструктор | ||
+ | Point(int iX,int iY){ | ||
+ | X=iX; | ||
+ | Y=iY; | ||
+ | } | ||
+ | |||
+ | // | ||
+ | void Show(){ | ||
+ | cout<<" | ||
+ | cout<<" | ||
+ | cout<<" | ||
+ | } | ||
+ | |||
+ | // перегруженный оператор + | ||
+ | // метод класса для ситуации Point+int | ||
+ | Point& | ||
+ | Point P(0,0); | ||
+ | P.X=X+d; | ||
+ | P.Y=Y+d; | ||
+ | return P; | ||
+ | } | ||
+ | // функции доступа к | ||
+ | // privat-членам без них | ||
+ | // глобальная перегрузка невозможна | ||
+ | int GetX() const{ | ||
+ | return X; | ||
+ | } | ||
+ | int GetY() const{ | ||
+ | return Y; | ||
+ | } | ||
+ | void SetX(int iX){ | ||
+ | X=iX; | ||
+ | } | ||
+ | void SetY(int iY){ | ||
+ | Y=iY; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // глобальная перегрузка | ||
+ | // для ситуации int + Point | ||
+ | // доступ к private-членам | ||
+ | // через специальные функции | ||
+ | Point& | ||
+ | Point P(0,0); | ||
+ | P.SetX(d+Z.GetX()); | ||
+ | P.SetY(d+Z.GetY()); | ||
+ | return P; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | // создание объекта | ||
+ | Point A(3,2); | ||
+ | A.Show(); | ||
+ | |||
+ | // | ||
+ | Point B=A+5; | ||
+ | B.Show(); | ||
+ | |||
+ | // | ||
+ | Point C=2+A; | ||
+ | C.Show(); | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | Без глобальной перегрузки задача int + Point не решается. Поскольку мы не можем получить доступ к " | ||
+ | |||
+ | Примечание: | ||
+ | Перегрузка ввода/ | ||
+ | Для того, что бы закрепить новую полученную информацию о перегрузке рассмотрим возможность перегрузить операторы << и >>. Для начала немного информации - | ||
+ | |||
+ | Выполнение любой программы С++ начинаются с набором предопределенных открытых потоков, | ||
+ | |||
+ | cin - объект класса istream (Потоковый класс общего назначения для ввода, являющийся базовым классом для других потоков ввода) | ||
+ | |||
+ | cout - объект класса ostream (Потоковый класс общего назначения для вывода, | ||
+ | |||
+ | Вывод в поток выполняется с помощью операции, | ||
+ | |||
+ | Для ввода информации из потока используется операция извлечения, | ||
+ | |||
+ | Чтобы избежать неожиданностей, | ||
+ | |||
+ | 1. Возвращаемым значением для операций ввода и вывода должна являться ссылка на поток, чтобы несколько операций могли быть выполнены в одном выражении. | ||
+ | |||
+ | 2. Первым параметром функции должен быть поток, из которого будут извлекаться данные, | ||
+ | |||
+ | 3. Чтобы разрешить доступ к закрытым данным класса, | ||
+ | |||
+ | 4. В операцию вывода необходимо передавать константную ссылку на объект класса, | ||
+ | |||
+ | Итак, рассмотрим пример подобной перегрузки: | ||
+ | < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс " | ||
+ | class Point | ||
+ | { | ||
+ | // координаты точки | ||
+ | int X; | ||
+ | int Y; | ||
+ | | ||
+ | |||
+ | // конструктор | ||
+ | Point(int iX,int iY){ | ||
+ | X=iX; | ||
+ | Y=iY; | ||
+ | } | ||
+ | // дружественные функции перегрузки ввода и вывода данных | ||
+ | friend istream& | ||
+ | friend ostream& | ||
+ | |||
+ | }; | ||
+ | //ввод данных через поток | ||
+ | istream& | ||
+ | cout<<" | ||
+ | is >> P.X; | ||
+ | cout<<" | ||
+ | is >> P.Y; | ||
+ | return is; | ||
+ | } | ||
+ | // | ||
+ | ostream& | ||
+ | os << "X = " << P.X << ' | ||
+ | os << "Y = " << P.Y << ' | ||
+ | return os; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | // создание объекта | ||
+ | Point A(0,0); | ||
+ | |||
+ | // одиночный ввод и вывод | ||
+ | cin>> | ||
+ | cout<< | ||
+ | |||
+ | // множественное выражение | ||
+ | Point B(0,0); | ||
+ | cin>> | ||
+ | cout<< | ||
+ | } | ||
+ | </ | ||
+ | В одном из примеров мы использовали константный метод - метод, который не имеет право изменять поля класса. Однако, | ||
+ | |||
+ | Проиллюстрируем особенности оформления операции-функции в виде дружественной функции класса. | ||
+ | < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс реализующий работу | ||
+ | // с логическим значением | ||
+ | class Flag | ||
+ | { | ||
+ | bool flag; | ||
+ | // дружественная функция (перегрузка | ||
+ | // оператора ! - замена значения флага | ||
+ | // на противоположное) | ||
+ | friend Flag& operator !(Flag& | ||
+ | | ||
+ | |||
+ | // Конструктор. | ||
+ | Flag(bool iF) | ||
+ | { | ||
+ | flag = iF; | ||
+ | } | ||
+ | // Компонентная функция показа значения флага | ||
+ | // в текстовом формате: | ||
+ | void display(){ | ||
+ | if(flag) cout<<" | ||
+ | else cout<<" | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Определение дружественной | ||
+ | // операции-функции. | ||
+ | // (this не передается, | ||
+ | Flag& operator !(Flag & f) | ||
+ | { | ||
+ | // | ||
+ | f.flag=!f.flag; | ||
+ | return f; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | Flag A(true); | ||
+ | |||
+ | // показ начального значения | ||
+ | A.display(); | ||
+ | |||
+ | // замена значения на противоположное | ||
+ | // с помощью перегруженного оператора | ||
+ | A=!A; | ||
+ | // показ измененного значения | ||
+ | A.display(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Результат выполнения программы: | ||
+ | |||
+ | TRUE | ||
+ | |||
+ | FALSE | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ====== Глобальная перегрузка. ====== | ||
+ | В C++ кроме двух известных вам разновидностей перегрузки (перегрузка в классе и дружественная перегрузка), | ||
+ | <note important> | ||
+ | Допустим, | ||
+ | < | ||
+ | a+b означает a.operator+(b) | ||
+ | </ | ||
+ | Однако, | ||
+ | < | ||
+ | C operator+(C, | ||
+ | </ | ||
+ | Такой вариант перегрузки тоже применим к выражению a+b, где a и b передаются соответственно в первом и втором параметрах функции. Из этих двух форм предпочтительной считается перегрузка в классе. Т. к. вторая форма требует открытого обращения к членам класса, | ||
+ | |||
+ | Смешивать эти две формы в программе не рекомендуется. Если для некоторого оператора определены обе формы с одинаковыми типами формальных параметров, | ||
+ | |||
+ | Тем не менее, глобальная перегрузка операторов обеспечивает симметрию, | ||
+ | |||
+ | < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс " | ||
+ | class Point | ||
+ | { | ||
+ | // координаты точки | ||
+ | int X; | ||
+ | int Y; | ||
+ | | ||
+ | |||
+ | // конструктор | ||
+ | Point(int iX,int iY){ | ||
+ | X=iX; | ||
+ | Y=iY; | ||
+ | } | ||
+ | |||
+ | // | ||
+ | void Show(){ | ||
+ | cout<<" | ||
+ | cout<<" | ||
+ | cout<<" | ||
+ | } | ||
+ | |||
+ | // перегруженный оператор + | ||
+ | // метод класса для ситуации Point+int | ||
+ | Point& | ||
+ | Point P(0,0); | ||
+ | P.X=X+d; | ||
+ | P.Y=Y+d; | ||
+ | return P; | ||
+ | } | ||
+ | // функции доступа к | ||
+ | // privat-членам без них | ||
+ | // глобальная перегрузка невозможна | ||
+ | int GetX() const{ | ||
+ | return X; | ||
+ | } | ||
+ | int GetY() const{ | ||
+ | return Y; | ||
+ | } | ||
+ | void SetX(int iX){ | ||
+ | X=iX; | ||
+ | } | ||
+ | void SetY(int iY){ | ||
+ | Y=iY; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // глобальная перегрузка | ||
+ | // для ситуации int + Point | ||
+ | // доступ к private-членам | ||
+ | // через специальные функции | ||
+ | Point& | ||
+ | Point P(0,0); | ||
+ | P.SetX(d+Z.GetX()); | ||
+ | P.SetY(d+Z.GetY()); | ||
+ | return P; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | // создание объекта | ||
+ | Point A(3,2); | ||
+ | A.Show(); | ||
+ | |||
+ | // | ||
+ | Point B=A+5; | ||
+ | B.Show(); | ||
+ | |||
+ | // | ||
+ | Point C=2+A; | ||
+ | C.Show(); | ||
+ | } | ||
+ | </ | ||
+ | Без глобальной перегрузки задача int + Point не решается. Поскольку мы не можем получить доступ к " | ||
+ | |||
+ | < | ||
+ | ====== Перегрузка ввода/ | ||
+ | Для того, что бы закрепить новую полученную информацию о перегрузке рассмотрим возможность перегрузить операторы << и >>. Для начала немного информации - | ||
+ | Выполнение любой программы С++ начинаются с набором предопределенных открытых потоков, | ||
+ | |||
+ | cin - объект класса istream (Потоковый класс общего назначения для ввода, являющийся базовым классом для других потоков ввода) | ||
+ | cout - объект класса ostream (Потоковый класс общего назначения для вывода, | ||
+ | |||
+ | Вывод в поток выполняется с помощью операции, | ||
+ | |||
+ | Для ввода информации из потока используется операция извлечения, | ||
+ | |||
+ | Чтобы избежать неожиданностей, | ||
+ | |||
+ | - Возвращаемым значением для операций ввода и вывода должна являться ссылка на поток, чтобы несколько операций могли быть выполнены в одном выражении. | ||
+ | - Первым параметром функции должен быть поток, из которого будут извлекаться данные, | ||
+ | - Чтобы разрешить доступ к закрытым данным класса, | ||
+ | - В операцию вывода необходимо передавать константную ссылку на объект класса, | ||
+ | |||
+ | Итак, рассмотрим пример подобной перегрузки: | ||
+ | < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | // класс " | ||
+ | class Point | ||
+ | { | ||
+ | // координаты точки | ||
+ | int X; | ||
+ | int Y; | ||
+ | | ||
+ | |||
+ | // конструктор | ||
+ | Point(int iX,int iY){ | ||
+ | X=iX; | ||
+ | Y=iY; | ||
+ | } | ||
+ | // дружественные функции перегрузки ввода и вывода данных | ||
+ | friend istream& | ||
+ | friend ostream& | ||
+ | |||
+ | }; | ||
+ | //ввод данных через поток | ||
+ | istream& | ||
+ | cout<<" | ||
+ | is >> P.X; | ||
+ | cout<<" | ||
+ | is >> P.Y; | ||
+ | return is; | ||
+ | } | ||
+ | // | ||
+ | ostream& | ||
+ | os << "X = " << P.X << ' | ||
+ | os << "Y = " << P.Y << ' | ||
+ | return os; | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | // создание объекта | ||
+ | Point A(0,0); | ||
+ | |||
+ | // одиночный ввод и вывод | ||
+ | cin>> | ||
+ | cout<< | ||
+ | |||
+ | // множественное выражение | ||
+ | Point B(0,0); | ||
+ | cin>> | ||
+ | cout<< | ||
+ | } | ||
+ | </ | ||
+ | < | ||
+ | ====== Дружественные классы ====== | ||
+ | Пора узнать, | ||
+ | |||
+ | Особенности " | ||
+ | - Дружественный класс должен быть определен вне тела класса, | ||
+ | - Все компонентные функции класса-друга будут являться дружественными для другого класса без указания спецификатора friend. | ||
+ | - Все компоненты класса доступны в дружественном классе, | ||
+ | - Дружественный класс может быть определен позже (ниже), чем описан как дружественный. | ||
📌 Удобный подбор VPS по параметрам доступен на DIEGfinder.com - официальном инструменте проекта DIEG. Это часть единой экосистемы, созданной для того, чтобы помочь быстро найти подходящий VPS/VDS сервер для любых задач хостинга.
📌 Для тестирования скриптов, установщиков VPN и Python-ботов рекомендуем использовать надежные VPS на короткий срок. Подробнее о быстрой аренде VPS для экспериментов - читайте здесь.
💥 Подпишись в Телеграм 💥 и задай вопрос по сайтам и хостингам бесплатно!7 Самых Популярных Статей
- Как запустить скрипты и веб-приложения на Python
- Что такое страны TIER 1,2,3
- 7 способов сравнения файлов по содержимому в Windows или Linux
- Установка и тестирование веб-панели HestiaCP
- Nginx простые примеры конфигурации
- top, htop, atop определение загрузки ОС (Load average, LA)
- Использование rsync в примерах
7 Самых Популярных Обзоров
- Хостинг для Python-скриптов и приложений
- ТОП 4 лучших антидетект браузеров (Бесплатные & Платные)
- Подборка купонов (промокоды) на хостинг, антидетект браузеры
- Обзор THE.Hosting (PQ Hosting): надежный хостинг с профессиональной поддержкой
- Хостинг в России
- Хостинг в Европе
- Обзор браузера Dolphin {anty} для мультиаккаунтинга