- •Часть 2
- •Оглавление
- •Понятие класса
- •Конструкторы
- •Деструкторы
- •Поля данных и методы класса
- •Внешнее определение методов класса
- •Создание многофайлового проекта
- •Команда make и make-файлы
- •Синтаксис make-файла
- •Опции и параметры команды make
- •Зависимости
- •Правила
- •Комментарии в make-файле
- •Практическое занятие 16. Дружественные функции. Перегруженные операции. Дружественные функции
- •Перегрузка операций
- •Перегрузка операции присваивания
- •Перегрузка операции индексирования
- •Перегрузка операции вызова функции ( )
- •Создание собственных функций вставки и извлечения
- •Void exit(int код_возврата);
- •Практическое занятие 17. Функторы
- •Практическое занятие 18. Создание иерархии классов.
- •Конструкторы и деструкторы при наследовании
- •Поля и методы при наследовании
- •Операция присваивания и принцип подстановки
- •Практическое занятие 19. Динамический полиморфизм. Абстрактные классы Виртуальные методы
- •Абстрактные классы
- •Virtual тип_возврата имя_функции
- •Рекомендуемая литература
Практическое занятие 16. Дружественные функции. Перегруженные операции. Дружественные функции
Дружественные функции класса определяются вне области действия этого класса, но имеют право доступа к закрытым элементам private (и к элементам protected) данного класса.
Правила описания и особенности дружественных функций:
дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, с ключевым слово friend. В качестве параметра ей должен передаваться объект, ссылка или указатель на объект класса, поскольку указатель this ей не передается.
дружественная функция может быть обычной функцией или методом ранее определенного класса. На нее не распространяется действие спецификаторов доступа, место размещения ее объявления в классе безразлично.
одна функция может быть дружественной сразу нескольким классам.
Использование механизма дружественных функций позволяет упростить интерфейс между классами. Например, дружественная функция позволит получить доступ к собственным или защищенным данным и методам сразу нескольких классов. Тем самым из классов можно иногда убрать методы, предназначенные только для доступа к этим "скрытым" полям данных и методам.
Рассмотрим пример: программа демонстрирует объявление и использование дружественной функции setX для установки закрытого элемента класса ClassOne.
//Листинг 16.1
#include<iostream>
using namespace std;
class ClassOne{
int x; //элемент данных
friend void setX(ClassOne &,int); //объявление друга
public:
ClassOne() {x=0;} //конструктор
void print() const {cout<<x<<"\n";} //вывод
};
//Можно изменять закрытую переменную класса ClassOne, так как setX //объявлена как дружественная функция класса ClassOne
void setX(ClassOne &c, int val)
{c.x=val; } //разрешено,т.к. setX - друг ClassOne
int main()
{ ClassOne object;
object.print();
setX(object,8); //задание x другом
object.print();
return 0;
}
Результаты выполнения программы:
0
8
Перегрузка операций
С++ позволяет переопределить действие большинства операций так, чтобы при использовании с объектами конкретного класса они выполняли заданные функции.
Формат определения функции-операции:
тип_возвращаемого_значения operator знак_операции
(список параметров)
{тело функции}
Определенная таким образом операция называется перегруженной, а сам механизм – перегрузкой, или расширением действия стандартных операций языка С++.
Обозначения собственных операций вводить нельзя. Можно перегружать любые операции, существующие в С++, за исключением:
. - прямой выбор метода или поля структурированного объекта;
.* - обращение к методу или полю данных через указатель на него;
?: - условная операция (тернарная);
:: - операция указания области видимости;
# - препроцессорная операция;
## - препроцессорная операция;
sizeof - операция вычисления размера (в байтах).
Перегрузка операций осуществляется с помощью методов специального вида (функций-операций) и подчиняется следующим правилам:
при перегрузке операций сохраняются количество аргументов, приоритеты операций и правила ассоциации (справа налево или слева направо), используемые в стандартных типах данных;
для стандартных типов данных переопределять операции нельзя;
нельзя вводить лексические обозначения операций, даже формируя их из допустимых символов (например, операцию возведения в степень ** из языка Фортрана нельзя ввести в С++);
функции-операции не могут иметь аргументов по умолчанию;
функции-операции наследуются (за исключением =);
функции-операции не могут определяться как static.
Функцию-операцию можно определить тремя способами, она должна быть:
либо методом класса;
либо дружественной функцией класса;
либо обычной функцией.
Когда функция-операция реализована как функция-элемент, крайний левый (или единственный) операнд должен быть объектом того класса (или ссылкой на объект того класса), элементом которого является функция. Если левый операнд должен быть объектом другого класса или встроенного типа, такая функция-операция не может быть реализована как функция-элемент.
В двух последующих случаях функция должна принимать хотя бы один аргумент, имеющий тип класса, указателя или ссылки на класс.
Определив операцию-функцию, можно обратиться к ней не только неявно, используя знак операции, но и явно:
operator знак операции(аргументы)
Унарную операцию класса можно перегружать как нестатическую функцию-элемент без аргументов, либо как функцию, не являющуюся элементом с одним аргументом; этот аргумент должен быть либо объектом класса, либо ссылкой, либо указателем на объект класса.
Бинарную операцию можно перегружать как нестатическую функцию-элемент с одним аргументом, либо как функцию, не являющуюся элементом, с двумя аргументами. Первым параметром дружественной функции, перегружающей бинарный оператор, является его левый операнд, а вторым – правый операнд.
Рассмотрим перегрузку некоторых специальных операторов.
