- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект cout
- •Манипуляторы hex и oct
- •Другие манипуляторы
- •Объект cin
- •Операторы для динамического выделения и освобождения памяти (new и delete)
- •Базовые конструкции объектно-ориентированных программ Объекты
- •Понятие класса
- •Конструктор копирования
- •Конструктор explicit
- •Указатели на компоненты класса
- •Встроенные функции (спецификатор inline)
- •Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •Вложенные классы
- •Static-члены (данные) класса
- •Указатель this
- •Компоненты-функции static и const
- •Proxi-классы
- •Параметры ссылки
- •Независимые ссылки
- •Практические приемы ограничения числа объектов класса
- •Наследование (производные классы)
- •Конструкторы и деструкторы при наследовании
- •Виртуальные функции
- •Абстрактные классы
- •Виртуальные деструкторы
- •Множественное наследование
- •Виртуальное наследование
- •Перегрузка функций
- •Перегрузка операторов
- •Перегрузка бинарного оператора
- •Перегрузка унарного оператора
- •Дружественная функция operator
- •Перегрузка оператора []
- •Перегрузка оператора ()
- •Перегрузка операторов new и delete
- •Преобразование типа
- •Явные преобразования типов
- •Преобразования типов, определенных в программе
- •Шаблоны Параметризированные классы
- •Передача в шаблон класса дополнительных параметров
- •Шаблоны функций
- •Совместное использование шаблонов и наследования
- •Шаблоны класса и friend
- •Некоторые примеры использования шаблона класса Реализация smart-указателя
- •Классы поддерживающие транзакции
- •Задание значений параметров класса по умолчанию
- •Пространства имен
- •Ключевое слово using как директива
- •Ключевое слово using как объявление
- •Псевдоним пространства имен
- •Организация ввода-вывода
- •Состояние потока
- •Строковые потоки
- •Организация работы с файлами
- •Организация файла последовательного доступа
- •Создание файла произвольного доступа
- •Основные функции классов ios, istream, ostream
- •Основы обработки исключительных ситуаций
- •Перенаправление исключительных ситуаций
- •Исключительная ситуация, генерируемая оператором new
- •Генерация исключений в конструкторах
- •Задание собственной функции завершения
- •Спецификации исключительных ситуаций
- •Задание собственного неожиданного обработчика
- •Иерархия исключений стандартной библиотеки
- •Стандартная библиотека шаблонов (stl) Общее понятие о контейнере
- •Общее понятие об итераторе
- •Категории итераторов
- •Основные итераторы
- •Вспомогательные итераторы
- •Операции с итераторами
- •Контейнерные классы Контейнеры последовательностей
- •Контейнер последовательностей vector
- •Контейнер последовательностей list
- •Контейнер последовательностей deque
- •Ассоциативные контейнеры
- •Ассоциативный контейнер multiset
- •Ассоциативный контейнер set
- •Ассоциативный контейнер multimap
- •Ассоциативный контейнер map
- •Адаптеры контейнеров
- •Адаптеры stack
- •Адаптеры queue
- •Адаптеры priority_queue
- •Пассивные и активные итераторы
- •Алгоритмы
- •Алгоритмы сортировки sort, partial_sort, sort_heap
- •Алгоритмы поиска find, find_if, find_end, binary_search
- •Алгоритмы fill, fill_n, generate и generate_n
- •Алгоритмы equal, mismatch и lexicographical_compare
- •Математические алгоритмы
- •Алгоритмы copy, copy_backward, merge, unique и reverse
- •Алгоритмы работы с множествами
- •Алгоритмы swap, iter_swap и swap_ranges
- •Примеры реализации контейнерных классов Связанные списки
- •Реализация односвязного списка
- •Реализация двусвязного списка
- •Реализация двоичного дерева
- •Литература
- •Вопросы по курсу ооп
- •220013, Минск, п.Бровки, 6.
Перегрузка оператора ()
Оператор вызова функции можно доопределить, как и любой другой оператор. Как и в предыдущем случае, оператор () необходимо перегружать только с помощью компоненты-функции, использование friend-функции запрещено. Общая форма функции operator()() имеет вид:
тип_возвр_значения имя_класса::operator ()(список_аргументов)
{ тело функции}
#include "iostream.h"
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]; // возврат требуемого элемента
}
void main()
{ matr mt(3,5);
cout << mt(2,3) << endl;
cout << mt(3,2) << endl; // попытка получить элемент из 3-й строки
cout << mt(3) << endl;
}
Результаты работы программы:
13
выход за пределы массива 0
6
Конструктор класса matr динамически выделяет и инициализирует память двухмерного массива. Деструктор разрушает массив автоматически при завершении программы. В классе matr реализованы две функции operator(): первая получает два аргумента (индексы в матрице), вторая получает один аргумент (порядковый номер элемента в матрице). Обе функции возвращают либо требуемый элемент, либо элемент m[0][0] при попытке выхода за пределы матрицы.
Перегрузка оператора ->
Оператор -> доступа к компонентам объекта через указатель на него определяется как унарный постфиксный.
Ниже приведен простой пример программы перегрузки оператора ->:
#include "iostream.h"
#include "iomanip.h"
#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;} // функция перегрузки ->
};
void 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];}
а также доопределение может быть выполнено по отношению к большинству рассмотренных ранее операций (+, ++ и др.).
