Перегрузка операторов дает возможность добавлять к встроенным типам данных в С++ новые типы. В зависимости от назначения перегрузка операторов объявляется так же, как и обычная дружественная функция или функция-член класса.
class ZZ {
public:
friend ZZ operator+(ZZa, ZZb);
friend ZZ operator-(ZZa, ZZb);
friend ZZ operator*(ZZa, ZZb);
friend ZZ operator/(ZZa, ZZb);
};
Имена функций — operator/, operator*, operator-, operator+ состоят из ключевого слова operator и символа операции.
Список операций, которые могут быть пререгружены
* / + — % ^ & :
— ! , = < > <= >=
++ — << >> == != && ||
*= /* %= ^= &= |= += -=
<<= >>= -> ->* [] () new delete
Не перегружаются операции: ::, *(разименование указателя), .(точка), ->. operator+(a, b); аналогично a + b; выполняется одно и тоже действие и генерируют одинаковый код.
Перегрузка не вносит в С++ ничего нового, только лишь позволяет использовать в выражениях объекты классов вместо того, чтобы передавать их в функции.
// Программа 4. Пример перегрузки операторов с помощью
// дружественных функций
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
class TStrOp {
private:
char val[12];
public:
TStrOp() { val[0]=0; }
TStrOp(const char* s);
long GetVal(void) { return atol(val);}
friend long operator+(TStrOp a, TStrOp b);
friend long operator-(TStrOp a, TStrOp b);
};
void main()
{
TStrOp a = «1234»;
TStrOp b = «4321»;
cout << endl << «value of a == » << a.GetVal();
cout << endl << «value of b == » << b.GetVal();
cout << endl << » a + b + 6 == » << ( a + b + 6 );
cout << endl << » a — b + 10 == » << ( a — b + 10 )
<< endl;
}
TStrOp::TStrOp(const char* s)
{
strncpy(val, s, 11);
val[11]=0;
}
long operator+(TStrOp a, TStrOp b)
{
return (atol(a.val) + atol(b.val));
}
long operator-(TStrOp a, TStrOp b)
{
return (atol(a.val) — atol(b.val));
}
Перегруженные функции могут быть членами класса. Отличие состоит только в определении функции, где указывается членом какого класса является данная перегружаемая функция.
class TStrOp {
private:
char val[12];
public:
TStrOp() { val[0]=0; }
TStrOp(const char* s);
long GetVal(void) { return atol(val);}
long operator+(TStrOp b);
long operator-(TStrOp b);
};
long TStrOp::operator+(TStrOp b)
{
return (atol(val) + atol(b.val));
}
long TStrOp::operator-(TStrOp b)
{
return (atol(val) — atol(b.val));
}
3.3.1. Перегрузка унарных операторов
Унарные операторы могут быть объявлены как функции-члены, не имеющие аргументов, так и дружественными функциями.
long operator -(void) //Унарный минус
{ return -atol(val); }
friend long operator-(TStrOp a)
{ return -atol(a.val); }
3.3.2. Оператор индексирования массива
Можно перегрузить оператор индексирования массива [] для реализации доступа к данным-членам класса, подобного доступу к элементу массива, даже если эти данные имеют вид отдельных членов класса или связного списка.
// Программа 5 Пример перегрузки индексирования
#include <iostream.h>
class Psevdoarray {
private:
int val0;
int val1;
int val2;
int val3;
public:
Psevdoarray( int v0, int v1, int v2, int v3)
{ val0 = v0; val1 = v1; val2 = v2; val3 = v3;}
int GetInt(unsigned i);
int operator[] (unsigned i);
};
void main()
{
Psevdoarray pa(10, 20, 30,40);
for( int i=0; i<=3; i++)
cout << «pa[» << i << «] ==» << pa[i] << endl;
}
int Psevdoarray::GetInt(unsigned i)
{
switch (i) {
case 0: return val0;
case 1: return val1;
case 2: return val2;
case 3: return val3;
default: return val0;
}
}
int Psevdoarray::operator[](unsigned i)
{
return GetInt(i);
}
3.3.3. Оператор вызова функции
Перегрузка вызова функции operator() делает объект класса похожим на функцию, которую можно вызывать. Перегруженная функция может возвращать значения заданных ипов или ничего не возвращать. Кроме того, в ней могут быть объявлены параметры.
class X {
int x;
public:
int operator()(void);
X(int n) { x=n; }
};
int X::operator()(void)
{
return x;
}
main()
{
X object = 100;
int g == object(); //выглядит как вызов функции
cout << q; //на самом деле object.operator()();
return 0;
}
3.3.4. Перегрузка операторов new и delete
Для перегрузки new следует использовать прототип функции вида: void * operator new(size_t size); В дальнейшем обращение к оператору new для выделения памяти объектам класса будут перенаправлены замещающей функции. Функция должна возвращать адрес памяти, выделенной объекту. Вместо кучи можно выделять память из статического буфера, на диске или другом запоминающем устройстве.
// Программа 6
#include <iostream.h>
class DemoNew {
private:
int x;
public:
DemoNew();
void * operator new(size_t size);
};
char buf[512];
int index;
void main()
{
cout << endl << «Creating local instance»;
DemoNew b1;
cout << endl << «Allocating space via new»;
DemoNew *b2 = new DemoNew;
DemoNew *b3 = new DemoNew;
DemoNew *b4 = new DemoNew;
DemoNew *b5 = new DemoNew;
}
DemoNew::DemoNew()
{
cout << endl << «Inside constructor»;
x = index;
}
void *DemoNew::operator new(size_t size)
{
cout << endl << «Inside overloaded new. Size == «<< size;
if ( index >=512 — sizeof(DemoNew)) //Проверка наличия
return 0; //пространства в buf
else {
int k = index;
index+= sizeof(DemoNew);
return &buf[k];
}
}
Оператор delete служит для удаления объектов, адресованных указателями. Прототип функции перегрузки оператора delete должен иметь вид: void operator delete(void *p); , где р ссылается на удаляемый объект.
void operator delete(void *p);
void DemoNew::operator delete(void *p)
{
cout << endl << «Deleting object at «<< p;
}
Поскольку объекты не запоминаются в куче, то перегру-женный оператор ничего не освобождает.
