- •Тема 1.Понятие технологии программирования (2 часа). 3
- •Тема 2. Основные концепции ооп (2 часа). 7
- •Тема 3. Конструкторы и деструкторы (2 часа). 12
- •Тема 5. Дружественные функции (friend functions) (2 часа) 32
- •Тема 6. Обработка исключительных ситуаций (2 часа) 44
- •Тема 8. Производные классы (2 часа) 76
- •Тема 9. Виртуальные функции (2 часа) 83
- •Тема 10. Множественное наследование. Производные классы векторов (2 часа) 90
- •Тема 12. Шаблоны функций и классов. 128
- •Тема 14. Применение оо-подхода в базах данных 148
- •Тема 1.Понятие технологии программирования (2 часа).
- •1.1. Предмет изучения курса ооп
- •1.2. Исторический экскурс
- •1.3. Основные технологии программирования
- •1.4. Заключение
- •Тема 2. Основные концепции ооп (2 часа).
- •2.1. Объекты и классы
- •2.1.1.Понятие класса объектов
- •2.1.2. Основные характеристики состояния класса
- •2.1.3. Понятие инкапсуляции свойств объекта
- •2.1.4. Структура глобальной памяти класса и глобальные методы класса
- •2.1.5. Интерфейс класса
- •2.1.6. Функции-члены класса
- •2.2. Понятие наследования (Inheritance)
- •2.3. Понятиеполиморфизма
- •Тема 3. Конструкторы и деструкторы (2 часа).
- •3.1. Для чего нужны конструкторы
- •3.2. Использование конструкторов «по умолчанию»
- •3.3. Использование деструкторов
- •3.4. Демонстрация последовательности работы конструкторов и деструкторов
- •3.5. Конструктор копирования
- •3.6. Определение операции присваивания
- •3.6.1. Пример использования конструктора копирования.
- •3.7.1. Краткий обзор библиотеки stl
- •3.7.2. Вектора
- •3.8. Inline-подстановка
- •4.1. Перегрузка операторов
- •4.1.1. Пример на перегрузку операторов
- •4.1.2. Общие принципы перегрузки операторов
- •4.1.3. Бинарные и Унарные Операции
- •4.2. Пример с перегрузкой операторов
- •Тема 5. Дружественные функции (friend functions) (2 часа)
- •5.1. Примеры использования дружественных функций
- •5.2. Особенности перегрузки префиксной и постфиксной форм унарных операций
- •5.3. Статические члены данных
- •5.4. Перегрузка операторов new, new[], delete, delete[]
- •Void* operator new(size_t размер){ код оператора
- •Void operator delete(void* p){ код оператора }
- •Void* operator new[](size_t размер){ код оператора return указатель_на_память; }
- •Void operator delete[](void* p){ код оператора }
- •Тема 6.Обработка исключительных ситуаций(2 часа)
- •6.1. Применение try, catch, throw
- •6.2. Синтаксис и семантика генерации и обработки исключений
- •6.3. Обработка исключений
- •6.4. Обработка исключений при динамическом выделении памяти
- •6.5. Функции, глобальные переменные и классы поддержки механизма исключений
- •6.6. Конструкторы и деструкторы в исключениях
- •7.1 Строковые типы
- •7.1.1. Преобразования, определяемые классом
- •7.1.2. Встроенный строковый тип
- •7.1.3 Класс string
- •7.2. Пример строкового класса с перегруженными операторами и дружественными функциями
- •Тема8.Производные классы (2 часа)
- •8.1. Определение производного класса
- •8.2. Правила использования атрбутов доступа
- •8.3. Конструкторы и деструкторы производных классов
- •Тема 9. Виртуальные функции (2часа)
- •9.1. Определение виртуальных методов
- •9.2. Абстрактные классы
- •9.3. Таблицы виртуальных методов (функций)
- •9.4. Выводы
- •Тема 10. Множественное наследование. Производные классы векторов (2 часа)
- •10.1. Множественное наследование
- •10.2. Отношения между классами
- •10.2.3. Ассоциация
- •10.2.4. Агрегирование
- •10.2.5. Наследование
- •10.3. Библиотека графических объектов (пример)
- •10.3.1. Динамический полиморфизм и наследование интерфейсов
- •10.3.2.Абстрактные классы
- •10.3.3. Множественное наследование в библиотеке графичкских фигур.
- •10.3.4. Иерархия классов библиотеки графичкских фигур
- •10.3.5. Таблица наследования
- •10.3.6. Диаграмма модулей
- •10.3.7.Директивы препроцессора
- •10.4. Производные классы векторов
- •10.5. Операции над векторами
- •11.1. Потоковый ввод-вывод
- •11.1.1. Классы потоков
- •11.1.2. Стандартные потоки
- •11.2.Опрос и установка состояния потока
- •11.3.Перегрузка операций извлечения и вставки в поток
- •11.4.Переадресация ввода-вывода
- •11.5. Операции помещения в поток и извлечения из потока
- •11.6.Форматирование потока
- •11.7.Файловый ввод-вывод с использованием потоков
- •11.8.Бесформатный ввод-вывод
- •11.9.Часто применяемые функции библиотеки ввода / вывода
- •11.10.Файлы с произвольным доступом
- •11.11. Буферизация
- •11.12. Заключение
- •Тема 12. Шаблоны функций и классов.
- •12.1 Шаблоны функций
- •12.2. Шаблоны классов
- •12.3. Размещение определений шаблонов в многомодульных программах
- •12.4. Полиморфные вектора
- •13.1 Область видимости
- •13.1.1. Локальная область видимости
- •13.2. Глобальные объекты и функции
- •13.2.1. Объявления и определения
- •13.2.2. Несколько слов о заголовочных файлах
- •13.3. Локальные объекты
- •13.3.1. Автоматические объекты
- •13.3.2. Регистровые автоматические объекты
- •13.3.3. Статические локальные объекты
- •13.4. Динамически размещаемые объекты
- •13.4.1. Динамическое создание и уничтожение единичных объектов
- •13.5. Определения пространства имен а
- •Тема 14. Применение оо-подхода в базах данных
- •14.1. Реляционные базы данных
- •14.2 Объектно-ориентированные базы данных (ообд)
- •14.3. Гибридные базы данных
- •Рекомендуемая литература
11.2.Опрос и установка состояния потока
Класс iosподдерживает информацию о состоянии потока после каждой операции ввода-вывода. Текущее состояние потока хранится в объекте типаiostate, который объявлен следующим образом:
typedef int iostate;
Состояния потока являются элементами перечислимого типа io_state, который может иметь значения, представленные в табл. 11.2.
Таблица 11.2. Состояния потока и их значения
Состояние |
Значение |
Goodbit |
Ошибок нет |
Eofbit |
Достигнут конец файла |
Failbit |
Имеет место ошибка форматирования или преобразования |
Badbit |
Имеет место серьезная ошибка |
Для опроса и установки состояния потока можно использовать функции-члены класса ios. Имеется два способа получения информации о состоянии операции ввода-вывода. Во-первых, можно вызвать функциюrdstate(),имеющую прототипiostate rdstate() const.
Функция возвращает состояние операции ввода-вывода. Во-вторых, можно воспользоваться одной из следующих функций-членов:
int good() const; int eof() const; int fail() const; int bad() const;
Каждая из этих функций возвращает 1, если установлен соответствующий бит состояния (точнее, функция fail() возвращает 1, если установлен бит failbit или badbit).
Если прочитано состояние, которое сигнализирует об ошибке, его можно сбросить с помощью функции clear ():
void clear(iostate state = ios::goodbit);
Установить нужное состояние можно с помощью функции setsfate():
void setstate(iostate state);
Кроме перечисленных функций, класс iosсодержит функцию приведения типа operator void*() const; (она возвращает NULL, если установлен бит badbit) и перегруженный оператор логического отрицания
int operator !() const;
(он возвращает 1, если установлен бит badbit). Это позволяет сравнивать выражения, в которые входит поток или его отрицание с нулем, то есть писать выражения вида:
while(!strm.eof()) { ... }
Следующий пример иллюстрирует получение информации о состоянии ввода-вывода.
#include < iostream.h > #include < fstream.h > int main(int argc, char* argv[])
{ char c; if (argc > 1){ ifstream ifs(argv[1]); if (!ifs){ cout << "Файл не открыт\n"; return 1; } while (ifs.eof()) { ifs.get©; // Контроль состояния потока if (ifs.fail ()) {cout << "Ошибка \n"; break; } cout << с; } ifs.close(); } return 0; }
В этом примере осуществляется ввод символов из файла, заданного в командной строке при запуске программы. Если при извлечении символов встречается ошибка, чтение прекращается и выводится сообщение об этом.
11.3.Перегрузка операций извлечения и вставки в поток
Одним из главных преимуществ потоков ввода-вывода является их расширяемость для новых типов данных. Можно реализовать операции извлечения и вставки для своих собственных типов данных. Чтобы избежать неожиданностей, ввод-вывод для определенных пользователем типов данных должен следовать тем же соглашениям, которые используются операциями извлечения и вставки для встроенных типов данных. Рассмотрим пример перегрузки операций извлечения и вставки в поток для определенного пользователем типа данных, которым является следующий класс даты:
class Date { public: Date(int d, int m, int y); Date(const tm & t); Date(); private: tm tm_date; };
Этот класс содержит член типа tm, который представляет собой структуру для хранения даты и времени, определенную в заголовочном файле time.h. Чтобы осуществить ввод-вывод пользовательского типа данных, какими являются объекты класса Date, нужно перегрузить операции извлечения и вставки в поток для этого класса. Приведем соответствующее объявление класса Date:
class Date { tin tm_date; friend istream & operator>> ( istream fi is, Date dat); friend ostream& operator<< (ostream& os, const Date& dat); public: Date(int d, int m, int y); Date(tm t); Date(); tin tm_date; friend istream & operator>> ( istream fi is, Date dat); friend ostream& operator<< (ostream& os, const Date& dat); };
Реализуем операции извлечения и вставки для объектов класса Date.
Возвращаемым значением для операции извлечения (и вставки) должна являться ссылка на поток, чтобы несколько операций могли быть выполнены в одном выражении. Первым параметром должен быть поток, из которого будут извлекаться данные, вторым параметром - ссылка или указатель на объект определенного пользователем типа. Чтобы разрешить доступ к закрытым данным класса, операция извлечения должна быть объявлена как дружественная функция класса. Ниже приведена операция извлечения из потока для класса Date:
istream .& operator>>( istream & is, Date& dat)
{ is >> dat.tm_date.tm_mday; is >> dat.tm_date.tm_mon; is >> dat.tm_date.tm_year; return is; }
Те же самые замечания верны и для операции вставки. Она может быть построена аналогично. Единственное отличие заключается в том, что в нее нужно передать константную ссылку на объект типа Date, поскольку операция вставки не должна модифицировать выводимые объекты. Ниже приведена ее реализация для класса Date:
osiream& operator<<(ostream& os, const Date& dat){ os << dat.tm_date.tm_mday << '/'; os << dat.tm_date.tin_mon << '/'; os << dat.tm_date.tm_year; return os; }
Следуя соглашениям о вводе-выводе для потоков, теперь можно осуществлять извлечение и вставку объектов класса Date следующим образом:
Date birthday(24,10,1985); cout << birthday << '\n'; или
Date date; cout << "Пожалуйста, введите дату (день, месяц, год)\n"; cin >> date; cout << date << '\n';
Приведем теперь пример полностью:
#include < iostream.h > #include < time.h > class Date { tm tm_date; public: Date(int d, int m, int y) { tm_date.tm_mday = d; tm_date.tm_mon = m; tm_date.tm_year = y; }; Date (tm t){tm_date = t;}; Date() { tm_date.tm_mday = 01; tm_date.tm_mon = 00; tm_date.tm_year = 00; } friend ostream& operator<< (ostream& os, const Date& dat); friend istream & operator>> ( istream & is, Date& dat); }; istream & operator>>( istream & is, Date& dat){ is >> dat.tm_date.tm_mday; is >> dat.tm_date.tm_mon ; is >> dat.tm_date.tm_year ; return is; } ostream& operator<< (ostream& os,const Date& dat){ os << dat.tm_date.tm_mon << '/' ; os << dat.tm_date.tm_mday << '/' ; os << dat. tm_date. tm_year ; return os; }
void main(){ Date date; cout << "Пожалуйста, введите дату (день, месяц, год)\n"; cin >> date; cout << date << '\n'; }
Приведем еще один пример, демонстрирующий перегрузку операций извлечения и вставки в поток, на этот раз для структуры:
struct info { char *name; double val; char *units; info(){ val=0; name = new char [30]; units = new char [30]; name[0]=units[0]=0; }}; ostream& operator << (ostream& s, info &m){ // Вывод info в s s << m.name << " "<< m.val <<" "<< m.units<< "\n"; return s;}
Oперация >> может быть перегружена следующим образом:
istream & operator >> ( istream & s, info &m){ // Ввод в info s.width(30); s >> m.name; char c; while((c = s.get())!= ' ' && c!='\t' && c!='\n'); s.putback©; s.width(30); s >> m.val; s.width(30); s >> m.units; return s; }
Для считывания строки ввода, такой как "Resistance 300 Ohm", можно использовать следующую запись:
void main(){ clrscr(); info m; cout<< "Введите наименование величины, ее значение \n"; cout<< " и единицу измерения (и нажмите Enter.):\n"; cin >> m; // Переопределенная операция >> cout << m; // Переопределенная операция << }
При выполнении этой программы диалог на экране монитора может выглядеть следующим образом:
Введите наименование величины, ее значение и единицу измерения (и нажмите Enter.):
Resistance 300 Ohm Resistance 300 Ohm