7. Друзья
Дружественной функцией класса называется функция, которая, не являясь его компонентом, имеет доступ к его защищенным и собственным компонентам.
Функция не может стать другом класса “без его согласия”. Для получения прав друга функция должна быть описана в теле класса со спецификатором friend. Именно при наличии такого описания класс предоставляет функции права доступа к защищенным и собственным компонентам.
class C
{ …
friend class A; }
Все функции класса A имеют доступ к закрытым полям класса C.
Дружба не носит ”сквозного” характера (не обладает свойством транзитивности): если класс A друг класса B, а класс B друг класса C, то это не означает, что A друг C.
Отметим особенности дружественных функций. Дружественная функция при вызове не получает указателя this. Объекты классов должны передаваться дружественной функции только явно через аппарат параметров. При вызове дружественной функции нельзя использовать операции выбора:
имя_объекта.имя_функции и указатель_на_объект->имя_функции
8. Перегрузка операцийНа все операции языка C++, кроме операций объявления, new, delete, и других операций, связанных с определением производных типов данных, распространяется свойство полиморфизма, т.е. возможности использования в различных случаях для одной и той же операции операндов различных типов. Так, например, операция сложения позволяет “смешивать” типы int, double, float и другие в одном выражении. Такой полиморфизм обеспечен внутренними механизмами языка C++.
Таким образом, нельзя перегружать такие операции: . :: * ?:
Чтобы появилась возможность использовать стандартную для языка C++ операцию с необычными для нее данными, необходимо специальным образом определить ее новое поведение. Это возможно, если хотя бы один из операндов является объектом некоторого класса, т.е. введенного пользователем типа. В этом случае применяется механизм, во многом схожий с механизмом определения функций. Для распространения действия операции на новые пользовательские типы данных программист определяет специальную функцию, называемую “операция-функция” (operator function). Формат определения операции-функции:
тип_возвращаемого_значения operator знак_операции (спецификация параметров операции-функции) {операторы тела операции-функции}
При необходимости может добавляться и прототип операции-функции с таким форматом:
тип_возвращаемого_значения operator знак_операции (спецификация параметров операции-функции);
И в прототипе, и в заголовке определения операции-функции используется ключевое слово operator, вслед за которым помещен знак операции. Если принять, что
конструкция operator знак_операции есть имя некоторой функции, то определение и прототип операции-функции подобны определению и прототипу обычной функции языка C++. Например, для распространения действия бинарной операции * на объекты класса T может быть введена функция с заголовком T operator *(T x, T y).
Определенная таким образом операция (в нашем примере операция “ звездочка”) называется перегруженной (по-английски - overload), а сам механизм – перегрузкой или расширением действия стандартных операций языка C++.
Количество параметров у операции-функции зависит от арности операции и от способа определения функции. Операция-функция определяет алгоритм выполнения перегруженной операции, когда эта операция применяется к объектам класса, для которого операция-функция введена. Чтобы явная связь с классом была обеспечена, операция-функция должна быть либо компонентом класса, либо она должна быть определена в классе как дружественная, либо у нее должен быть хотя бы один параметр типа класс (или ссылка на класс).
Если для класса T введена операция-функция с приведенным выше заголовком и определены два объекта A и B класса T,то выражение A*B интерпретируется как вызов функции operator * (A,B).
Рассмотрим пример. Реализуем перегрузку операции сложения для класса комплексных чисел.
class comp
{float im; float real;
public:
comp(float i, float r)
{real=r;
im=i;}
comp operator +(comp X)
{return comp(im+X.im, real+X.real);}
}
void main()
{ …
comp C1(1,1), C2(5,5),C3;
C3=C1.operator+(C2) // Прямой вызов операции-функции. Не используется.
C3=C1+C2 // Косвенный вызов операции-функции.
…
}
Компилятор по типам объектов С1 и С2 определяет, что необходимо реализовать не просто сложение двух скаляров, как это бывает в обычном использовании операции +, а вызвать перегруженную функцию operator +.Так как при определении класса поля im и real доступны функциям класса, есть необходимость определять только второй объект (X в нашем примере).
В языке C++ требуется, чтобы операции присваивания, индексации и косвенного обращения к полям класса (->) обязательно определялись как методы, т.е. как функции-члены класса.
Когда левый операнд операции является представителем класса, перегруженную операцию нужно определять как метод этого класса.
Для многих операций C++ существуют свои особенности при перегрузке (доопределении). Так, унарные операции переопределяются с описанием операции-функции без аргумента, например:
class A
{ …
A operator --() {текст функции}
… }
Соответственно доопределение бинарной операции использует описание операции-функции с одним аргументом, т.к. вторым является объект, для которого вызвана операция. Следует также помнить, что операция присваивания “=” может перегружаться только объявлением метода без описателя static. То же относится к операциям “()” и ”[]”.
Посмотрим, как будет выглядеть перегрузка операции присваивания для примера с комплексными числами.
comp & operator =([const] comp & X)
{real=X.real;
im=X.im;
return *this;}
Если указываем const, то это показывает, что параметр не должен изменяться внутри функции, а кроме того, позволяет обрабатывать константные объекты.
Операция присваивания не наследуется.
Константные объекты и константные методы
const Loc NK(0,0); //константный объект
После инициализации попытки изменения константного объекта отслеживаются и пресекаются компилятором.
Объявление константной функции в теле класса выглядит следующим образом:
Прототип const;
ПРАВИЛО:
Константные методы
1) не должны менять значения элементов класса;
2) не должны вызывать другие неконстантные методы класса.
Константные методы могут применяться как для константных, так и для неконстантных объектов.
Литература
1. М.Уэйт, С.Прата, Д.Мартин Язык Си: Пер с англ.-М.: Мир, 1988.-463 с.,ил.
2. Уинер Р. Язык Турбо Си: Пер с англ.-М.: Мир, 1991.-384 с.,ил.
3. Берри Р., Микинз Б. Язык Си: введение для программистов: Пер. с англ.-М.:Финансы и статистика, 1988.-с.,ил.
4. TURBO C++. Borland International. Inc. 1990.
... различных свойств. В результате выполнения методов объекта могут происходить новые события, воспринимаемые другими объектами программы или пользователем. 2. Интегрированная среда разработки Delphi: назначение и общее описание среды Delphi – это потомок среды программирования Turbo Pascal. Название среды произошло от названия города в Древней Греции, где находился знаменитый Дельфийский ...
... , сколько времени потребуется для его составления, как много места для возможных ошибок? Естественно, об этом задумывались и авторы языков программирования. Поэтому во всех существующих языках имеются типы переменных, отвечающие за хранение больших массивов данных. В языке Паскаль они так и называются: "массивы". Массивом будем называть упорядоченную последовательность данных одного типа, ...
... урожай который может быть обеспечен генетическим потенциалом сорта и приходом ФАР при реально существующих среднемноголетних условиях и применением агротехники. В Свердловской области величина действительно возможного урожа в основном определяется влагообеспеченностью, особенно продуктивной ее частью, которая рассчитывается по данным годового количества осадков. Таблица 7 Среднемноголетние ...
... следует до заморозков. Засилосованные початки в молочно – восковой спелости приравниваются по количеству кормовых единиц (на сухое вещество) к спелому зерну кукурузы. Следовательно, целесообразно их убирать и силосовать отдельно от стеблей и листьев. Технология возделывания и уборки кукурузы Уточни с препадом на счет дат и вид работ. 1 и 2 переставь местами строчки. № Виды работ Объем ...
0 комментариев