- •2.5. Простейший ввод и вывод
- •2.5.1. Объект cin
- •2.5.2. Объект cout
- •2.5.3. Манипуляторы
- •2.6. Операторы для динамического выделения и освобождения памяти (new и delete)
- •5. Перегрузка
- •5.1. Перегрузка функций
- •5.2. Перегрузка операторов
- •5.2.1. Перегрузка бинарного оператора
- •5.2.2. Перегрузка унарного оператора
- •5.2.3. Дружественная функция operator
- •5.2.5. Перегрузка оператора []
- •5.2.6. Перегрузка оператора ()
- •5.2.8. Перегрузка операторов new и delete
- •6. Шаблоны
- •6.1. Параметризированные классы
- •6.2. Передача в шаблон класса дополнительных параметров
- •6.3. Шаблоны функций
- •6.4. Совместное использование шаблонов и наследования
- •6.5. Шаблоны класса и friend-функции
- •7.1. Организация ввода-вывода
- •7.2. Состояние потока
- •7.3. Строковые потоки
- •7.4. Организация работы с файлами
- •7.5. Организация файла последовательного доступа
- •Istream& seekg( streampos pos );
- •Istream& seekg( streamoff off, ios::seek_dir dir );
- •7.6. Создание файла произвольного доступа
- •7.7. Основные функции классов ios, istream, ostream
- •8.1. Основы обработки исключительных ситуаций
- •8.2. Перенаправление исключительных ситуаций
- •8.3. Исключительная ситуация, генерируемая оператором new
- •8.4 Генерация исключений в конструкторах
- •8.5. Задание собственной функции завершения
- •8.6. Спецификации исключительных ситуаций
- •8.7. Задание собственного неожиданного обработчика
- •8.8. Иерархия исключений стандартной библиотеки
5.2.6. Перегрузка оператора ()
Оператор вызова функции можно доопределить, как и любой другой оператор. Как и в предыдущем случае, оператор () необходимо перегружать только с помощью компоненты-функции, использование friend-функции запрещено. Общая форма функции operator()() имеет вид
тип_возвр_значения имя_класса::operator ()(список_аргументов)
{ тело функции}
#include <iostream>
using namespace std;
class matr
{ int **m,a,b;
public:
matr(int,int);
~matr();
int operator()(int,int); // перегрузка оператора ()
int operator()(int); // перегрузка оператора ()
};
matr::matr(int i,int j): a(i),b(j) // конструктор
{ i=0;
m=new int *[a];
for(int k=0; k<a; k++)
{ *(m+k)=new int[b];
for(int n=0; n<b; n++)
*(*(m+k)+n)=i++; // заполнение m числами 0,1,2,3, …a*b
}
}
matr::~matr() // деструктор
{ for(int k=0; k<a; k++)
delete [] m[k]; // освобождение памяти для k-й строки
delete [] m; // освобождение памяти для всего массива
} // указателей m
int matr::operator()(int i,int j)
{ if (i<0 || i>=a || j<0 || j>=b)
{ cerr<<"выход за пределы матрицы ";
return m[0][0]; // например, при этом возврат m[0][0]
}
return m[i][j]; // возврат требуемого элемента
}
int matr::operator()(int i)
{ if (i<0 || i>=a*b)
{ cerr<<"выход за пределы массива ";
return **m; // как и выше возврат m[0][0]
}
return m[i/b][i%b]; // возврат требуемого элемента
}
int main()
{ matr mt(3,5);
cout << mt(2,3) << endl;
cout << mt(3,2) << endl; // попытка получить элемент из 3-й строки
cout << mt(3) << endl;
return 0;
}
Результаты работы программы:
13
выход за пределы массива 0
6
Конструктор класса matr динамически выделяет и инициализирует память двухмерного массива. Деструктор разрушает массив автоматически при завершении программы. В классе matr реализованы две функции operator(): первая получает два аргумента (индексы в матрице), вторая получает один аргумент (порядковый номер элемента в матрице). Обе функции возвращают либо требуемый элемент, либо элемент m[0][0] при попытке выхода за пределы матрицы.
5.2.7. Перегрузка оператора ->
Оператор -> доступа к компонентам объекта через указатель на него определяется как унарный постфиксный.
Ниже приведен простой пример программы перегрузки оператора ->:
#include <iostream>
#include <iomanip>
using namespace std;
#include "string.h"
class cls_A
{ char a[40];
public:
int b;
cls_A(char *aa,int bb): b(bb) // конструктор
{strcpy(a,aa);}
char *put_A() {return a;}
};
class cls_B
{ cls_A *p; // указатель на объект класса cls_A
public:
cls_B(char *aa,int bb) {p=new cls_A(aa,bb);} // конструктор
~cls_B() {delete p;} // деструктор
cls_A *operator->(){return p;} // функция перегрузки ->
};
int main()
{ cls_B ptr("перегрузка оператора -> ",2); // объект класса cls_B
cout << ptr->put_A() << setw(6) << ptr->b <<endl; // перегрузка ->
cout << (ptr.operator->())->put_A() << setw(6)
<< (ptr.operator->())->b <<endl;
cout << (*ptr.operator->()).put_A() << setw(6)
<< (*ptr.operator->()).b <<endl;
}
Результат работы программы:
перегрузка оператора -> 2
перегрузка оператора -> 2
перегрузка оператора -> 2
В приведенной программе инструкции ptr->put_A() и ptr->b приводят к перегрузке операции ->, т.е. позволяют получить адрес указателя на компненты класса cls_A для (из) объекта ptr. Таким образом, инструкция ptr->b соответствует инструкции (ptr.p)->b. Следующие далее две группы инструкций также верны, но не являются примером перегрузки оператора ->, а только приводят к явному вызову функции operator-> - компоненты класса cls_B.
В целом доопределение оператора -> позволяет использовать ptr с одной стороны как специальный указатель (в примере для класса cls_A), а с другой стороны как объект (для класса cls_B).
Специальные указатели могут быть доопределены следующим образом:
cls_A &operator*(){return *p;}
cls_A &operator[](int index){return p[index];}
а также доопределение может быть выполнено по отношению к большинству рассмотренных ранее операций (+, ++ и др.).