cpp-oop (823968), страница 15
Текст из файла (страница 15)
Тогда из этих классовможно убрать компонентные функции, предназначенные только для обеспечения доступак «скрытым» компонентам.ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»109Поскольку ограничение доступа к дружественной функции не относится, работатьона будет достаточно быстро, и написать ее не труднее, чем функцию доступа к обычнойструктуре С++.Если необходимо, чтобы все функции некоторого класса имели доступ к внутреннимполям другого класса, то весь класс может быть объявлен дружественным:friend class <Имя класса >.Пример 4.5. Объявление дружественного класса.#include <locale.h>#include <iostream>using namespace std;class SHOW; // объявление класса без его определенияclass PAIR{private:char *Head,*Tail;public:PAIR(char *one,char *two):Head(one),Tail(two){}friend class SHOW;// объявление дружественного класса};class SHOW/* всем функциям класса SHOW доступны внутренниеполя класса PAIR*/{private:PAIR Twins;public:SHOW(char *one,char *two):Twins(one,two){}void Head() { cout <<Twins.PAIR::Head << endl; }void Tail() { cout <<Twins.PAIR::Tail << endl; }};void main(){setlocale(0,"russian");SHOW aa("ПРИВЕТ","ДРУЗЬЯ");cout << "Результаты работы:"<<endl;ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»110aa.Head();// выводит:ПРИВЕТaa.Tail();// выводит:ДРУЗЬЯsystem("pause");}ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»111Вопросы для самоконтроля1. Что собой представляют локальные классы? Для чего они используются?Ответ.2. Что такое статические компоненты класса? Чем они отличаются от обычныхкомпонентов? Зачем используются?Ответ.3. Что такое дружественные функции и дружественные классы? Как определитьдружественные функции? Где и как они используются?Ответ.ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»11255.1Переопределение операцийФункции-операторы, их типы и ограничения на переопределениеВ языке С++ операции над стандартно определенными типами данных являютсявстроенными, т. е. программист не может повлиять на выполнение этих операций. Однакоязык предоставляет возможность переопределения любой из существующих операций дляобъектов вновь созданных классов.При переопределении операций ни одно из ее исходных значений не теряется.Просто вводится операция с похожим смыслом для объектов нового класса.Переопределяемые операции реализуются как особый вид функции со специальнымименем operator@, где @ – символ переопределяемой операции.
Такие функции обычноназываются функциями-операторами. Функция-оператор может быть определена каккомпонент класса или как внешняя независимая от класса (свободная) функция.Соответственно различают:• простую, т. е. определенную вне класса функцию-оператор;• компонентную, т. е. определенную в классе функцию-оператор.И простые, и компонентные функции-операторы могут быть одноместными идвуместными. В первом случае у них один параметр, а во-втором – два.
ЕдинственнуюсуществующуювС++операциюстремяпараметрами(условнуюоперацию)переопределять запрещено.Одноместныеидвуместныефункции-операторывзависимостиотместапереопределения (в классе или вне его) описываются по-разному. Это связано с тем, чтопервый аргумент компонентной функции – всегда объект класса, задаваемый неявно, апотому одноместная компонентная функция объявляется без списка параметров,двуместная – с одним параметром.Общая форма определения функции-оператора представлена в табл. 5.1.
Вприведенных в таблице описаниях символ @ – любая допустимая операция, <Типрезультата> – тип возвращаемого значения (чаще всего того же типа, что и класс, хотявозможен и другой тип этого значения).ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»113Таблица 5.1. Формы описанияфункции-оператораПростая функцияКомпонентная функцияодноместнаяодноместная<Тип результата> operator @ (Аргумент)<Тип результата> operator @ ()двуместнаядвуместная<Тип результата> operator @ (Арг1,Арг2)<Тип результата>operator @ (Арг2.)При переопределении операций следует помнить, что• нельзя переопределять операции *, sizeof, ?:, #, ##, ::, class::;• операции =, [], () можно переопределять только в составе класса;• переопределенная операция = не наследуется в производных классах;• нельзя изменять приоритет и ассоциативность операции (порядок выполненияопераций одного приоритета).Функция-оператор допускает две формы вызова: стандартную и операторную,описанные в табл.
5.2.Таблица 5.2 Формы вызова функции – оператораСтандартная формаОператорная формаДля простой функцииДля простой функцииoperator @ (<Аргумент>)@<Аргумент>operator @ (<Аргумент1>,<аргумент2>)<Аргумент1>@<Аргумент2>для компонентной функциидля компонентной функции<Аргумент>.operator@()@<Аргумент><Аргумент1>.operator@(<Аргумент2>)<Аргумент1>@<Аргумент2>ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»1145.2Описание компонентных функций-операторовКак было сказано выше при описании компонентной функции-оператора первыйаргумент всегда объект класса, второй при необходимости передается через параметры.При переопределении операций следует различать ситуации, когда возвращаетсяадрес (ссылка или указатель) уже существовавшего объекта или новый объект. В первомслучае возвращаемое значение описывается как <Имя класса> & или <Имя класса> *, афункция-оператор должна вернуть *this или this соответственно. Во втором –возвращаемое значение указывается как <Имя класса>, в классе создается новый объект ифункция-оператор должна вернуть этот объект.Пример 5.1.
Описание компонентной функции-оператора (класс Точка).#include <iostream>using namespace std;class TPoint{private:float x,y;public:TPoint(float ax,float ay):x(ax),y(ay){}TPoint(){}void Out(void){cout<<"\n{"<<x<<","<<y<<"}\n"; }// -a – одноместная операцияTPoint& operator-(){x=-x;y=-y;return *this;TPoint& operator+=(TPoint &p){x+=p.x; y+=p.y;TPoint pp(x,y);// a+=b – двуместная операцияreturn *this;TPoint operator+(TPoint &p){}}// a+b – двуместная операцияreturn pp+=p;}};void main(){TPoint p(2,3),q(4,5),r(7,8);ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»115-q;q.Out();p+=r;p.Out();q=p+r;q.Out();system("pause");}Фактически при выполнении операций p+=r, q=p+r выполняется еще однаоперация – операция присваивания. Такая операция предусмотрена для всех типов поумолчанию.
При выполнении этой операции происходит копирование полей методом«поле за полем». В рассмотренном классе отсутствуют динамические поля, поэтомустандартное определение операции присваивания переопределять не надо. При наличиидинамических полей переопределение этой операции обязательно (см. раздел 5.4).ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»1165.3Описание внешних функций-операторовФункции-операторы программируют как внешние, если необходимо, чтобы первыйаргумент операции не был объектом класса.
Внешней функции-оператору доступнытолько общие компоненты класса. Если необходимо, чтобы такая функция-операторимела возможность обращаться к внутренним или скрытым компонентам класса, то ееследует описать в классе со спецификатором friend, определив ее дружественной этомуклассу.Так при переопределении некоторых операций для обеспечения их коммутативностинеобходимоописыватьнескольковариантовфункций-операторов.Посколькуукомпонентной функции-оператора первый параметр всегда объект, коммутативныеоперации обычно переопределяют как внешние.Пример 5.2. Переопределение коммутативной операции «умножение на скаляр»(класс Целое число).
Переопределение операций продемонстрируем на примере описаниякласса Целое число (см. пример 2.2), для которого переопределим операцию умноженияцелого числа на скаляр «*».#include <locale.h>#include <stdio.h>#include <stdlib.h>#include <iostream>using namespace std;typedef unsigned long dlong;class Tlong{public:dlongnum;Tlong(){}Tlong(dlong an) { setnum(an);}friend Tlong & operator *(Tlong&,int k);friend Tlong & operator *(int k,Tlong&);void print(void);void setnum(dlong an) { num=an;}};ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»117Tlong & operator *(Tlong & ob1,int k){Tlong *temp=new Tlong;temp->num=ob1.num*k;return *temp;}Tlong & operator *(int k,Tlong &ob2){Tlong *temp=new Tlong;temp->num=ob2.num*k;return *temp;}void Tlong::print(){cout<<"Значениечисла : "<<num<<endl;}Tlong a(424567),c,d;long intn;void main(){setlocale(0,"russian");d=a*2;cout<<"d=a*2:"; d.print();c=operator *(2,a);cout<<"с=2*a:"; c.print();system("pause");}Двуместная операция умножения для обеспечения коммутативности описанадважды: для случая, когда второй операнд – скаляр, и для случая, когда первый операнд –скаляр.При работе с классами библиотеки ввода-вывода С++ следует помнить, что этиклассы поддерживают операции «<<» (включение в поток) и «>>» (извлечение из потока)только для стандартных типов данных.