- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект 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.
Ключевое слово using как объявление
Объявление using имя::член подобно директиве, при этом оно обеспечивает более подробный уровень управления. Обычно using используется для объявления некоторого имени (из пространства имен) как принадлежащего текущей области действия (блоку).
#include <iostream.h>
namespace NAME
{ int n1=1;
int n2=2;
}
int main()
{ NAME::n1=3;
// n1=4; error 'n1' надо указывать полностью NAME::n1
// n2=5; error 'n2' : undeclared identifier
// int n2; следующая строка приводит к ошибке
using NAME::n2; // далее n2 доступно
n2=6;
cout <<NAME::n1<<" "<< n2 << endl; // результат 3 6
{ NAME::n1=7;
n2=8;
cout <<NAME::n1<<" "<< n2 << endl;// результат 7 8
}
return 1;
}
В результате выполнения программы получим:
3 6
7 8
Объявление using добавляет определенное имя в текущую область действия. В примере к переменной n2 можно обращаться без указания принадлежности классу, а для n1 необходимо полное имя. Объявление using обеспечивает более подробное управление именами, переносимыми в пространство имен. Это и есть ее основное отличие от директивы, которая переносит все имена пространства имен.
Внесение в локальную область (блок) имени, для которого выполнено явное объявление (и наоборот), является серьезной ошибкой.
Псевдоним пространства имен
Псевдоним пространства имен существует для того, чтобы назначить другое имя именованному пространству имен.
namespace spisok_name_peremen // пространство имен
{ int n1=1;
. . .
}
NAME = spisok_name_peremen; // псевдоним пространства имен
Пространству имен spisok_name_peremen назначается псевдоним NAME. В этом случае результат выполнения инструкций:
cout <<NAME::n1<< endl;
cout<< spisok_name_peremen::n1<<endl;
будет одинаков.
Организация ввода-вывода
Системы ввода-вывода С и С++ основываются на понятии потока. Поток в С++ это абстрактное понятие, относящееся к переносу информации от источника к приемнику. В языке С++ реализованы 2 иерархии классов, обеспечивающих операции ввода-вывода, базовыми классами которых являются streambuf и ios. На рис.6 приведена диаграмма классов, базовым для которых является ios (рис. 6).
В
С++ используется достаточно гибкий
способ выполнения операций ввода-вывода
классов с помощью перегрузки операторов
<< (вывода) и >> (ввода). Операторы,
перегружающие эти операции, обычно
называют инсертером и экстрактором.
Для обеспечения работы с потоками
ввода-вывода необходимо включить файл
iostream.h, содержащий класс iostream. Этот класс
является производным от ряда классов,
таких как ostream, обеспечивающего вывод
данных в поток, и istream - соответственно
чтения из потока. Приводимый ниже пример
показывает, как можно перегрузить
оператор ввода-вывода для произвольных
классов.
#include "iostream.h"
class cls
{ char c;
short i;
public :
cls(char C,short I ) : c(C), i(I){}
~cls(){}
friend ostream &operator<<(ostream &,const cls);
friend istream &operator>>(istream &,cls &);
};
ostream &operator<<(ostream &out,const cls obj)
{ out << obj.c<<obj.i << endl;
return out;
}
istream &operator>>(istream &in,cls &obj)
{ in >> obj.st>>obj.i;
return in;
}
main()
{ cls s(’a’,10),ss(’ ’,0);
сout<<"abc"<<endl;
cout<<s<<ss<<endl;
cin >> ss;
return 0;
}
Общая форма функции перегрузки оператора ввода-вывода имеет вид:
istream &operator>>(istream &поток,имя_класса &объект)
ostream &operator<<(ostream &поток,const имя_класса объект)
Как видно, функция принимает в качестве аргумента и возвращает ссылку на поток. В результате доопределенный оператор можно применить последовательно к нескольким операндам
cout <<s<<ss;
Это соответствует
(cout.operator<<(a)).operator<<(b);
В приведенном примере функция operator не является компонентом класса cls, так как левым аргументом (в списке параметров) такой функции должен быть this-указатель для объекта, инициирующего перегрузку. Доступ к private-данным класса cls осуществляется через friend-функцию operator этого класса.
Рассмотрим использование перегрузки операторов << и >> для определения новых манипуляторов. Ранее мы рассмотрели использование стандартных манипуляторов форматирования выводимой информации. Однако можно определить и новые манипуляторы без изменения стандартных. В качестве примера рассмотрим переопределение манипулятора с параметрами, задающего для выводимого дробного числа ширину поля и точность.
#include<iostream.h>
class manip
{ int n,m;
ostream & (*f)(ostream&,int,int) ;
public:
manip(ostream& (*F)(ostream&,int,int), int N, int M) :
f(F), n(N), m(M) {}
friend ostream& operator<<(ostream& s, const manip& obj)
{return obj.f(s,obj.n,obj.m);}
};
ostream& f_man(ostream & s,int n,int m)
{ s.width(n);
s.flags(ios::fixed);
s.precision(m);
return s;
}
manip wp(int n,int m)
{ return manip(f_man,n,m);
}
void main(void)
{ cout<< 2.3456 << endl;
cout<<wp(8,1)<<2.3456 << endl;
}
Компонента-функция put и вывод символов
Компонента-функция ostream::put() используется для вывода одиночного символа:
char c=’a’;
. . .
cout.put(c);
Вызовы функции put() могут быть сцеплены:
cout.put(c).put(’b’).put(’\n’);
в этом случае на экран выведется буква а, затем b и далее символ новой строки.
Компоненты-функции get и getline для ввода символов.
Функция istream::get() может быть использована в нескольких вариантах.
Первый вариант – функция используется без аргументов. Вводит символ из соответствующего потока одиночный символ и возвращает его значение. Если из потока прочитан признак конца файла, то get возвращает EOF.
#include<iostream.h>
main(void)
{ char c;
cout << сin.eof()<< "вводите текст" << endl;
while((c=cin.get())!=EOF)
cout.put(c);
cout << endl<<cin.eof();
return 0; }
В программе считывается из потока cin очередной символ и выводится с помощью функции put. При считывании признака конца файла завершается цикл while. До и после цикла выводится значение cin.eof(), равное false (выводится 0) до начала цикла и true (выводится 1) после его окончания.
Второй вариант – когда функция get() используется с одним символьным аргументом. Функция возвращает false при считывании признака конца файла, иначе - ссылку на объект класса istream, для которого вызывалась функция get.
. . .
while(сin.get(с))
cout.put(c);
. . .
При третьем варианте функция get() принимает три параметра: указатель на символьный массив (строку), максимальное число символов и ограничитель ввода (по умолчанию ’\n’). Ввод прекращается, когда считано число символов на один меньшее максимального или считан символ-ограничитель. При этом в вводимую строку добавляется нуль-символ. Символ-ограничитель из входного потока не удаляется, это при повторном вызове функции get приведет к формированию пустой строки.
сhar s[30];
. . .
сin.get(s,20)) // аналогично cin.get(s,20,’\n’)
cout<<s<<endl;
. . .
Функция isteram::getline() действует аналогично функции get() с тремя параметрами с тем отличием, что символ-ограничитель удаляется из входного потока.
Ниже коротко рассмотрены другие функции-компоненты класса istream.
