Перегрузка бинарного оператора

Функция operator для перегрузки (доопределения) бинарных операторов может быть описана двумя способами:

- как компонента-функция класса с одним аргументом;

- как глобальная функция (функция, описанная вне класса) с двумя аргументами.

При перегрузке бинарного оператора # выражение a#b может быть представлено при первом способе как a.operator#(b) или как operator #(a,b) при втором способе перегрузки.

Рассмотрим простой пример переопределения операторов *, = , > и == по отношению к объекту, содержащему декартовы координаты точки на плоскости. В примере использован первый способ перегрузки.

#include "iostream.h"

class dek_koord

{ int x,y; // декартовы координаты точки

public:

dek_koord(){};

dek_koord(int X,int Y): x(X),y(Y) {}

dek_koord operator*(const dek_koord);

dek_koord operator=(const dek_koord);

dek_koord operator>(const dek_koord);

int operator ==(const dek_koord);

void see();

};

dek_koord dek_koord::operator*(dek_koord a) // перегрузка операции *

{ dek_koord tmp; // локальный объект

tmp.x=x*a.x;

tmp.y= y*a.y;

return tmp;

}

dek_koord dek_koord::operator =(const dek_koord a)

{ x=a.x; // перегрузка операции =

y=a.y;

return *this;

}

dek_koord dek_koord::operator >(const dek_koord a)

{ if (x<a.x) x=a.x; // перегрузка операции >

if (y<a.y) y=a.y;

return *this;

}

int dek_koord::operator ==(const dek_koord a) // перегрузка операции ==

{ if (x==a.x && y==a.y) return 0; // 0 – координаты равны

if (x>a.x && y>a.y) return 1; //

if (x<a.x && y<a.y) return -1; //

else return 2; // неопределенность

}

void dek_koord::see() // функция просмотра содержимого объекта

{ cout << "координата х = " << x << endl;

cout << "координата y = " << y << endl;

}

void main()

{ dek_koord A(1,2), B(3,4), C;

int i;

A.see();

B.see();

C=A*B; // вначале перегрузка операции * затем =

C.see();

C=A>B; // компоненты объекта С принимают значение max от А и В

C.see();

i=A==B; // i получает значение сравненияA==B (-1,0,1,2….)

// cout << A==B << endl; // ошибка

// error binary '<<' : no operator defined which takes a right-hand operand

// of type 'class dek_koord' (or there is no acceptable conversion)

cout << (A==B) << endl; // верно

}

Результат работы программы:

координата х = 1

координата y = 2

координата х = 3

координата y = 4

координата х = 3

координата y = 8

координата х = 3

координата y = 4

В приведенной выше программе функцию перегрузки оператора * можно изменить, например, следующим образом:

dek_koord &dek_koord::operator*(const dek_koord &a)

{ x*=a.x;

y*=a.y;

return *this;

}

В этом примере функция operator* в качестве параметра получает ссылку на объект, стоящий в правой части выражения А*В, то есть на В. Ссылка – это второе имя (псевдоним) для одного и того же объекта. Более подробно ссылки будут рассмотрены позже. Функция operator* при вызове получает скрытый указатель на объект А и модифицирует неявные параметры (компоненты-данные объекта А – х и у). Возвращается значение по адресу this, то есть объект А. Возвращать ссылку на объект необходимо для реализации выражения вида A*B*C.

Следует отметить, что если в описании класса dek_koord присутствуют объявления двух функций перегрузки операции *:

class dek_koord

{ . . .

dek_koord operator*(const dek_koord );

dek_koord &operator*(const dek_koord &);

. . .

};

то возникает ошибка. Аналогично ошибка будет, если одна из функций является компонентой класса, а другая глобальной функцией.

Если возвращаемое значение функции operator является ссылкой, то в этом случае возвращаемое значение не может быть автоматической или статической локальной переменной.

Рассмотрим фрагмент программы, в которой функция operator* является глобальной.

class dek_koord

{ int x,y; // декартовы координаты точки

public:

. . .

int read_x(); // возвращает компоненту x

int read_y(); // возвращает компоненту y

void write_x(int); // модифицирует компоненту x

void write_y(int); // модифицирует компоненту y

. . .

};

int dek_koord::read_x(){return x;}

int dek_koord::read_y(){return y;}

void dek_koord::write_x(int a){x=a;}

void dek_koord::write_y(int a){y=a;}

dek_koord operator*(dek_koord a,dek_koord b) // перегрузка операции *

{ dek_koord tmp; // функция operator - глобальная

tmp.write_x(a.read_x()*b.read_x());

tmp.write_y(a.read_y()*b.read_y());

return tmp;

}

В глобальной функции operator* доступ к private данным локального объекта tmp возможен через public функции этого объекта, либо данные класса должны иметь атрибут public, что не отвечает принципу инкапсуляции. Кроме того, если функция operator является friend-функцией некоторого класса, то она имеет доступ к private компонентам этого класса. Это будет рассмотрено несколько позже.

Ниже приведен пример еще одной программы перегрузки оператора ”-“ для использования его при вычитании из одной строки другой.

#include <iostream.h>

#include <string.h>

Class String

{ char str[80]; // локальная компонента

public: // глобальные компоненты

void init (char *s); // функция инициализации

int operator - (String s_new); // прототип функции operator

} my_string1, my_string2; // описание двух объектов класса String

void String::init (char *s) // функция обеспечивает копирование

// строки аргумента(s) в строку-компоненту

{ strcpy(str,s);} // (str) класса String

int String::operator - (String s_new) // перегрузка оператора – (вычитания

// строк)

{ for (int i=0; str[i]==s_new.str[i]; i++)

if (!str[i]) return 0;

return str[i] - s_new.str[i];

}

void main(void)

{ char s1[51], s2[51];

cout <<"Введите первую строку не более 80 символов:" <<endl;

cin >>s1;

cout<<" Введите вторую строку не более 80 символов "<<endl;

cin>>s2;

my_string1.init(s1); //инициализация объекта my_string1

my_string2.init(s2); //инициализация объекта my_string2

cout <<"\nString1 - String2 = "; // вывод на экран разности двух строк

cout << my_string1 - my_string2 << endl;

}

Результат работы программы:

Введите первую строку не более 80 символов:

overload

Введите вторую строку не более 80 символов

function

String1 – String2 = 9

При перегрузке бинарного оператора с использованием компоненты-функции ей передается в качестве параметра только один аргумент. Второй аргумент получается посредством использования неявного указателя this на объект, компоненты которого модифицируются.

Наши рекомендации