- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект 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
- •Математические алгоритмы
- •Алгоритмы работы с множествами
- •Алгоритмы swap, iter_swap и swap_ranges
- •Алгоритмы copy, copy_backward, merge, unique и reverse
- •Примеры реализации контейнерных классов Связанные списки
- •Реализация односвязного списка
- •Реализация двусвязного списка
- •Реализация двоичного дерева
- •Литература
- •Вопросы по курсу ооп
- •220013, Минск, п.Бровки, 6.
Перегрузка унарного оператора
При перегрузке унарной операции функция operator не имеет параметров. Как и в предыдущем случае, модифицируемый объект передается в функцию-operator неявным образом, используя указатель this.
Унарный оператор, как и бинарный, может быть перегружен двумя способами:
как компонента-функция без аргументов;
как глобальная функция с одним аргументом.
Как известно, унарный оператор может быть префиксным и постфиксным. Для любого префиксного унарного оператора выражение #a может быть представлено при первом способе как a.operator#(), а при втором как #operator(a).
При перегрузке унарного оператора, используемого в постфиксной форме, выражение вида a# может быть представлено при первом способе как a.operator#(int) или как operator#(a,int) при втором способе. При этом аргумент типа int не существует и используется для отличия префиксной и постфиксной форм при перегрузке.
Ниже приведен пример программы перегрузки оператора ++ и реализации множественного присваивания. Для перегрузки унарного оператора ++, предшествующего оператору ++i, вызывается функция operator ++(). В случае если оператор ++ следует за операндом i++, то вызывается функция
operator++(int x), где х принимает значение 0.
#include "iostream.h"
class dek_koord
{ int x,y; // декартовы координаты точки
public:
dek_koord(){};
dek_koord(int X,int Y): x(X),y(Y) {}
void operator++();
void operator++(int);
dek_koord operator=(dek_koord);
void see();
};
void dek_koord::operator++() // перегрузка операции ++A
{ x++;}
void dek_koord::operator++(int) // перегрузка операции A++
{ y++;}
dek_koord dek_koord::operator =(dek_koord a)
{ x=a.x; // перегрузка операции =
y=a.y;
return *this;
}
void dek_koord::see()
{ cout << "координата х = " << x << endl;
cout << "координата y = " << y << endl;
}
void main()
{ dek_koord A(1,2), B, C;
A.see();
A++; // увеличение значения компоненты х объекта А
A.see(); // просмотр содержимого объекта А
++A; // увеличение значения компоненты у объекта А
A.see(); // просмотр содержимого объекта А
C=B=A; // множественное присваивание
B.see();
C.see();
}
Результат работы программы:
координата х = 1
координата y = 2
координата х = 1
координата y = 3
координата х = 2
координата y = 3
координата х = 2
координата y = 3
координата х = 2
координата y = 3
Дружественная функция operator
Функция operator может быть не только членом класса, но и friend-функцией этого класса. Как было отмечено ранее, friend-функции, не являясь компонентами класса, не имеют неявного указателя this. Следовательно, при перегрузке унарных операторов в функцию operator передается один, а бинарных – два аргумента. Необходимо отметить, что операторы: =, (), [] и -> не могут быть перегружены с помощью friend-функции operator.
#include "iostream.h"
class dek_koord
{ int x,y; // декартовы координаты точки
public:
dek_koord(){};
dek_koord(int X,int Y): x(X),y(Y) {}
friend dek_koord operator*(int,dek_koord);
friend dek_koord operator*(dek_koord,int);
dek_koord operator=(dek_koord);
void see();
};
dek_koord operator*(int k,dek_koord dk) // перегрузка операции int *A
{ dk.x*=k;
dk.y*=k;
return dk;
}
dek_koord operator*(dek_koord dk,int k) // перегрузка операции A*int
{ dk.x*=k;
dk.y*=k;
return dk;
}
dek_koord dek_koord::operator=(dek_koord dk)
{ x=dk.x;
y=dk.y;
return *this;
}
void dek_koord::see()
{ cout << "координата т.(х,y) = " << x<<’ ’ <<y<< endl;
}
void main()
{ dek_koord A(1,2), B;
A.see();
B=A*2; // увеличение значения объекта А в 2 раза
B.see(); // просмотр содержимого объекта B
}
Результат работы программы:
координата т.(х ,у)= 1 2
координата т.(х ,у)= 2 4
Особенности перегрузки операции =
Доопределение оператора = позволяет решить проблему присваивания, но не решает задачи инициализации, так как при инициализации должен вызываться соответствующий конструктор. В рассматриваемом случае это решается использованием конструктора копирования.
Конструктор выполняет все необходимые действия при вызове функции и копировании содержимого объекта в стек (из стека). Вызов конструктора копирования осуществляется при обращении к функции и передаче в нее в качестве параметра объекта (объектов), а также возврата значения (объекта) из функции.
#include "iostream.h"
#include "string.h"
class string
{ char *str; // символьная трока
int size; // длина символьной строки
public:
string(){}; // конструктор по умолчанию
string(int n,char *s) // конструктор с параметрами
{ str=new char[size=n>=(strlen(s)+1)? n : strlen(s)+1];
strcpy(str,s);
}
string(const string &); // конструктор копирования
~string(){}; // деструктор
friend string operator+(string, const string);
string &operator=(const string &);
void see();
};
string::string(const string &a) // описание конструктора копирования
{ str=new char[a.size+1]; // выделяем память под this->str (+1 под ’\0’)
strcpy(str,a.str); // копирование строки
size=strlen(str);
}
string operator+(string s1, const string s2) // перегрузка операции +
{ string ss;
ss.str=new char[ss.size=strlen(s1.str)+strlen(s2.str)+1];
for(int i=0; ss.str[i]=s1.str[i]; i++); // перезапись символа ’\0’
ss.str[i]=' '; // удаление ’\0’
for(int j=0; ss.str[i+1]=s2.str[j]; i++,j++); // дозапись второй строки
return ss;
}
string &string::operator =(const string &st) // перегрузка операции =
{ if(this!=&st) // проверка, не копирование ли объекта в себя
{ delete str; // освобождаем память старой строки
str=new char[size=st.size];// выделяем память под новую строку
strcpy(str,st.str);
}
return *this;
}
void string::see()
{ cout << this->str << endl;
}
void main()
{ string s1(10,"язык"), s2(30,"программирования"), s3(30," ");
s1.see();
s2.see();
string s4=s1; // это только вызов конструктора копирования
s4.see();
string s5(s1); // прямой вызов конструктора копирования
s5.see();
s1+s2; // перегрузка + (вызов функции operator +)
s1.see();
s3=s2; // перегрузка = (вызов функции operator =)
s3.see();
s3=s1+s2; //перегрузка операции + , затем операции =
s3.see();
}
Результаты работы программы:
язык
программирования
язык
язык
программирования
язык программирования
Инструкция string s4=s1 только вызывает конструктор копирования для объекта s4. В инструкции string s5(s1) выполняется прямой вызов конструктора копирования для объекта s5. Выполнение инструкции s1+s2 приводит к двум вызовам конструктора копирования (вначале для копирования в стек объекта s2, затем s1). После этого выполняется вызов функции operator+ для инструкции s1+s2. При выходе из функции (инструкция return ss) вновь выполняется вызов конструктора копирования. При выполнении инструкции s3=s2 конструктор копирования для копирования объекта s2 в стек не вызывался, так как параметр в operator= передан (и возвращен) по ссылке.
