Объектно-ориентированное программирование — Перегрузка операций
- Объектно-ориентированное программирование
- Локальные и глобальные переменные
- Подпрограммы и их аргументы
- Определение данных
- Операторы динамического распределения памяти
- Перегрузка функций и операций
- Правила составления перегружаемых функций и операций
- Класс как обобщение структуры
- Определение первичного класса
- Перегрузка операций
- Конструкторы
- Список инициализации
- Деструктор
- Дружественные классы
- Статические элементы класса
- Шаблоны функций
Операции могут быть перегружены с помощью составных и дружественных функций. Имя функции, соответствующей операции, получается добавлением символа операции к слову operator. Например,
class Bits
{
char *b;
int size;
public:
Bits operator+(const Bits&); // сложение
Bits operator-(const Bits&); // вычитание
Bits operator-(); // унарный минус
Friend Bits& operator^(const Bits&, const Bits&); //XOR
};
Если операция определяется с помощью составной функции, то эта функция имеет на один аргумент меньше, чем в том случае, когда операция определяется с помощью дружественной функции. Для составной функции первый аргумент предполагается равным *this. Например, для класса строки операцию сравнения относительно лексикографического (алфавитного) порядка можно определить с помощью приведённой ниже составной функции:
#include
class String
{
char *s;
int len;
public:
int operator<(String st)
{
return strcmp(s,st,s)<0;
}
};
То же самое с помощью дружественной функции определяется следующим образом
#include
class String
{
char *s;
int len;
public:
friend int operator<(String, String);
};
operator<(String str1, String str2)
{
return strcmp(str1.s, str2.s)<0;
}
Перегрузка операций позволяет определить для классов значения любых операций, исключая “.”, ”::”, ”.*”, ”?:”, sizeof. Отсюда вытекает, что разрешено определять операции для класса, символы которых равны:
newdelete
+ — * / % ^ &
| ~ ! = +=
-= *= /= %= ^= &= |=
= == != <=
>= && || ++ -- () []
-> ->*
Здесь стандартная операция ->* обозначает косвенное обращение к элементу класса (элементу структуры) через указатель на объект и указатель на этот элемент,
например,
class C
{
int *d;
friend int f(C *p);
};
int f(C *p) {return p->*d;}
Аналогично, операция .* обозначает прямое обращение к элементу класса по имени объекта и указателю на элемент.
Приведем пример перегрузки операции индексации [], обычно используемую для возвращения ссылки, что позволяет применять ее в операции присваивания с обеих сторон.
Пример. Пусть класс определен как строка символов. Определим операцию индексации, позволяющую читать и записывать i-й символ строки:
#include
#include
#include
// Класс строка
class String
{
// Закрытые элементы
char *s; // Сама строка
int len; // Её длина
public: // Общедоступные элементы
// Перегрузка операции []
char& operator[](int pos)
{
return s[pos];
}
// Инициализация строки
void init(char *s)
{
len=strlen(s); // Определение длины
String::s=new char[len+1]; // Выделение памяти под строку
strcpy(String::s, s); // Присваивание
}
// Вывод строки на экран
void show()
{
cout<
}
};
void main()
{
clrscr(); // Очистка экрана
String a; // Создаём строку
a.init("abc"); // Инициализируем её
cout<<"Начальное содержимое строки: ";
a.show(); // Выводим строку на экран
a[1]='c';
cout<<"Содержимое строки после операции a[1]=\'c\': ";
a.show(); // Выводим строку на экран
a[0]='b';
cout<<"Содержимое строки после операции a[0]=\'b\': ";
a.show(); // Выводим строку на экран
cout<<"Содержимое строки после операции a[0]=a[2]: ";
a[0]=a[2];
a.show(); // Выводим строку на экран
getch(); // Ожидание нажатия клавиши
}
Результаты работы программы
Начальное содержимое строки: abc
Содержимое строки после операции a[1]='c': acc
Содержимое строки после операции a[0]='b': bcc
Содержимое строки после операции a[0]=a[2]: ccc
Вызов операции возвращает адрес a[i]. Присваивание a[i]=x записывает в этот адрес x.
Операции ++ и -- могут быть как префиксными и записываться ++x или --x, так и постфиксными — x++, x--. Если определять префиксные операции через составные функции, то следует указать обычным образом тип возвращаемого значения. Например,
class A
{
A& operator++();
A& operator--();
};
Префиксные операции ++ и -- можно определить как дружественные функции от одной переменной, представляющие собой ссылку на объект данного класса. Например,
class A
{
friend A& operator++(A&);
friend A& operator--(A&);
};
Постфиксные операции ++ и -- определяются с помощью функций, имеющих дополнительный аргумент типа int, который на самом деле не используется. Например:
class A
{
int x;
public:
void operator++() { x=x+2;}
void operator++(int) { x=x+1;}
};
void main()
{
A b;
b++; // b.x увеличили на 1
++b; // b.x увеличили на 2
}