Перегрузка унарного оператора
При перегрузке унарной операции функция operator не имеет параметров. Как и в предыдущем случае, модифицируемый объект передается в функцию-operator неявным образом, используя указатель this. Унарный оператор, как и бинарный, может быть перегружен двумя способами: - как компонента-функция без аргументов; - как глобальная функция с одним аргументом. Как известно, унарный оператор может быть префиксным и постфиксным. Для любого префиксного унарного оператора выражение #a может быть представлено при первом способе как a.operator#(), а при втором как #operator(a). При перегрузке унарного оператора, используемого в постфиксной форме, выражение вида a# может быть представлено при первом способе как a.operator#(int) или как operator#(a,int) при втором способе. При этом аргумент типа int не существует и используется для отличия префиксной и постфиксной форм при перегрузке. Ниже приведен пример программы перегрузки оператора ++ и реализации множественного присваивания. Для перегрузки унарного оператора ++, предшествующего оператору ++i, вызывается функция operator ++(). В случае если оператор ++ следует за операндом i++, то вызывается функция operator++(int x), где х принимает значение 0. #include "iostream.h" Class dek_koord { int x,y; // декартовы координаты точки public: dek_koord(){}; dek_koord(int X,int Y): x(X),y(Y) {} void operator++(); void operator++(int); dek_koord operator=(dek_koord); void see(); }; void dek_koord::operator++() // перегрузка операции ++A { x++;} void dek_koord::operator++(int) // перегрузка операции A++ { y++;} dek_koord dek_koord::operator =(dek_koord a) { x=a.x; // перегрузка операции = y=a.y; return *this; } void dek_koord::see() { cout << "координата х = " << x << endl; cout << "координата y = " << y << endl; } void main() { dek_koord A(1,2), B, C; A.see(); A++; // увеличение значения компоненты х объекта А
A.see(); // просмотр содержимого объекта А ++A; // увеличение значения компоненты у объекта А A.see(); // просмотр содержимого объекта А C=B=A; // множественное присваивание B.see(); C.see(); } Результат работы программы: координата х = 1 координата y = 2 координата х = 1 координата y = 3 координата х = 2 координата y = 3 координата х = 2 координата y = 3 координата х = 2 координата y = 3
Дружественная функция operator Функция operator может быть не только членом класса, но и friend-функцией этого класса. Как было отмечено ранее, friend-функции, не являясь компонентами класса, не имеют неявного указателя this. Следовательно, при перегрузке унарных операторов в функцию operator передается один, а бинарных – два аргумента. Необходимо отметить, что операторы: =, (), [] и -> не могут быть перегружены с помощью friend-функции operator. #include "iostream.h" Class dek_koord { int x,y; // декартовы координаты точки public: dek_koord(){}; dek_koord(int X,int Y): x(X),y(Y) {} friend dek_koord operator*(int,dek_koord); friend dek_koord operator*(dek_koord,int); dek_koord operator=(dek_koord); void see(); }; dek_koord operator*(int k,dek_koord dk) // перегрузка операции int *A { dk.x*=k; dk.y*=k; return dk; } dek_koord operator*(dek_koord dk,int k) // перегрузка операции A*int { dk.x*=k; dk.y*=k; return dk; } dek_koord dek_koord::operator=(dek_koord dk) { x=dk.x; y=dk.y; return *this; } void dek_koord::see() { cout << "координата т.(х,y) = " << x<<’ ’ <<y<< endl; } void main() { dek_koord A(1,2), B; A.see(); B=A*2; // увеличение значения объекта А в 2 раза B.see(); // просмотр содержимого объекта B } Результат работы программы: координата т.(х,у)= 1 2 координата т.(х,у)= 2 4
Особенности перегрузки операции = Доопределение оператора = позволяет решить проблему присваивания, но не решает задачи инициализации, так как при инициализации должен вызываться соответствующий конструктор. В рассматриваемом случае это решается использованием конструктора копирования. Конструктор выполняет все необходимые действия при вызове функции и копировании содержимого объекта в стек (из стека). Вызов конструктора копирования осуществляется при обращении к функции и передаче в нее в качестве параметра объекта (объектов), а также возврата значения (объекта) из функции.
#include "iostream.h" #include "string.h" Class string { char *str; // символьная трока int size; // длина символьной строки public: string(){}; // конструктор по умолчанию string(int n,char *s) // конструктор с параметрами { str=new char[size=n>=(strlen(s)+1)? n: strlen(s)+1]; strcpy(str,s); } string(const string &); // конструктор копирования ~string(){}; // деструктор friend string operator+(string, const string); string &operator=(const string &); void see(); }; string::string(const string &a) // описание конструктора копирования { str=new char[a.size+1]; // выделяем память под this->str (+1 под ’\0’) strcpy(str,a.str); // копирование строки size=strlen(str); } string operator+(string s1, const string s2) // перегрузка операции + { string ss; ss.str=new char[ss.size=strlen(s1.str)+strlen(s2.str)+1]; for(int i=0; ss.str[i]=s1.str[i]; i++); // перезапись символа ’\0’ ss.str[i]=' '; // удаление ’\0’ for(int j=0; ss.str[i+1]=s2.str[j]; i++,j++); // дозапись второй строки return ss; } string &string::operator =(const string &st) // перегрузка операции = { if(this!=&st) // проверка, не копирование ли объекта в себя { delete str; // освобождаем память старой строки str=new char[size=st.size];// выделяем память под новую строку strcpy(str,st.str); } return *this; } void string::see() { cout << this->str << endl; } void main() { string s1(10,"язык"), s2(30,"программирования"), s3(30," "); s1.see(); s2.see(); string s4=s1; // это только вызов конструктора копирования s4.see(); string s5(s1); // прямой вызов конструктора копирования s5.see(); s1+s2; // перегрузка + (вызов функции operator +) s1.see(); s3=s2; // перегрузка = (вызов функции operator =) s3.see(); s3=s1+s2; //перегрузка операции +, затем операции = s3.see(); } Результаты работы программы: язык программирования язык язык программирования язык программирования Инструкция string s4=s1 только вызывает конструктор копирования для объекта s4. В инструкции string s5(s1) выполняется прямой вызов конструктора копирования для объекта s5. Выполнение инструкции s1+s2 приводит к двум вызовам конструктора копирования (вначале для копирования в стек объекта s2, затем s1). После этого выполняется вызов функции operator+ для инструкции s1+s2. При выходе из функции (инструкция return ss) вновь выполняется вызов конструктора копирования. При выполнении инструкции s3=s2 конструктор копирования для копирования объекта s2 в стек не вызывался, так как параметр в operator= передан (и возвращен) по ссылке.
Перегрузка оператора [] Как было отмечено выше, функция operator может быть с успехом использована для доопределения операторов С++ (в основном арифметические, логические и операторы отношения). В то же время в С++ существуют некоторые операторы, не входящие в число перечисленных, но которые полезно перегружать. К ним относится оператор []. Его необходимо перегружать с помощью компоненты-функции, использование friend- функции запрещено. Общая форма функции operator[]() имеет вид: тип_возвр_значения имя_класса::operator [](int i) { тело функции} Параметр функции необязательно должен иметь тип int, но он использован, так как operator[] в основном применяется для индексации. Рассмотрим пример программы с использованием перегрузки операции []: #include "iostream.h" Class massiv { float f[3]; public: massiv(float i,float j,float k){f[0]=i; f[1]=j; f[2]=k;} float operator[](int i) { return f[i];} // перегрузка оператора [] }; void main() { massiv ff(1,2,3); double f; int i; cout << "введите номер индекса "; cin >> i; cout <<"f["<< i <<" ]= " << ff[i] << endl; } В примере перегруженная функция operator[]() возвращает величину элемента массива, индекс которого передан в функцию в качестве параметра. Данная программа при небольшой модификации может позволить использовать оператор[] как справа, так и слева от оператора присваивания. Для этого необходимо, чтобы функция operator[]() возвращала не элемент, а ссылку на него. #include "iostream.h" Class massiv { float f[3]; public: massiv(float i,float j,float k){f[0]=i; f[1]=j; f[2]=k;} float &operator[](int i) // перегрузка оператора [] { if(i<0 || i>2) // проверка на выход за границы массива { cout << “Выход за пределы массива”<<endl; exit(1); } return f[i]; } }; void main() { massiv ff(1,2,3); int i; cout << "введите номер индекса "; cin >> i; cout <<"f["<< i <<" ]= " << ff[i] << endl; ff[i]=5; // если функция operator не возвращает ссылку,то компиля- // тор выдает ошибку =': left operand must be l-value cout <<"f["<< i <<" ]= " << ff[i] << endl; } Рассмотрим случай когда функция operator возвращает не ссылку, а указатель на модифицируемое значение. Внесем некоторые изменения в рассмотренную выше программу.
Class massiv { float f[3]; public: ... float *operator[](int i) // перегрузка оператора [] { ... return &f[i]; } }; void main() { massiv ff(1,2,3); ... *ff[i]=5; // функция operator возвращает указатель cout <<"f["<< i <<" ]= " << *ff[i] << endl; } В приведенном примере создается ложное впечатление, что ff является вектором указателей. Поэтому использование ссылки представляется более предпочтительным. Приведем еще один пример программы, использующей перегрузку operator[]. // перегрузка функции operator[] на примере вычисления n! #include "iostream.h" #include "values.h" // для определения константы MAXLONG Class fact { long l; public: long operator[](int); // перегрузка оператора [] }; long fact::operator[](int n) { long l; for (int i=0; i<=n; i++) //выбор буквы из уменьшаемой строки if(l>MAXLONG/i) cerr<<"ОШИБКА факториал числа "<<n<<" больше "<<MAXLONG; else l*=i; return l; } void main() { fact f; int i,k; cout << "введите число k для нахождения факториала" cin >> k; for (i=1; i<=k; i++) cout << i <<"! = " << f[i] << endl; } Перегрузка оператора () Оператор вызова функции можно доопределить, как и любой другой оператор. Как и в предыдущем случае, оператор () необходимо перегружать только с помощью компоненты-функции, использование friend- функции запрещено. Общая форма функции operator()() имеет вид:
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|