
- •1.2 Философские замечания
- •1.3 Процедурное программирование
- •1.4 Модульное программирование
- •1.5 Абстракция данных
- •1.6 Пределы абстракции данных
- •1.7 Объектно-ориентированное программирование
- •1.8 Концепции объектно-ориентированного программирования
- •1.8.1 Инкапсуляция
- •1.8.2 Полиморфизм
- •1.8.3 Наследование
- •1.10 Несколько полезных советов
- •2.2 Перегрузка функций
- •2.3 Перегрузка операторов
- •2.4 Наследование
- •2.5 Конструкторы и деструкторы
- •2.7 Два новых типа данных
- •Глава 3. Классы и объекты
- •3.1 Параметризованные конструкторы
- •3.2 Дружественные функции
- •3.3 Значения аргументов функции по умолчанию
- •3.3.1 Корректное использование аргументов по умолчанию
- •3.4 Взаимосвязь классов и структур
- •3.5 Связь объединений и классов
- •3.6 Анонимные объединения
- •3.7 Inline-функции
- •3.7.1 Создание inline-функций внутри класса
- •3.8 Передача объектов в функции
- •3.9 Возвращение объектов функциями
- •3.10 Присваивание объектов
- •3.11 Конструктор копирования
- •3.12 Массивы объектов
- •3.12.1 Инициализация массивов объектов
- •3.12.2 Создание инициализированных и неинициализированных массивов
- •3.13 Указатели на объекты
- •3.14 Статические члены класса
- •Глава 4. Перегрузка функций и операторов
- •4.1 Перегрузка конструкторов
- •4.2 Локализация переменных
- •4.3 Локализация создания объектов
- •4.4 Перегрузка функций и неопределенность
- •4.5 Определение адреса перегруженной функции
- •4.6 Указатель this
- •4.7 Перегрузка операторов
- •4.8 Дружественная функция-оператор
- •4.9 Ссылки
- •4.9.1 Параметры-ссылки
- •4.9.2 Передача ссылок на объекты
- •4.9.3 Возврат ссылок
- •4.9.4 Независимые ссылки
- •4.9.5 Использование ссылок для перегрузки унарных операторов
- •4.10 Перегрузка оператора []
- •4.11 Создание функций преобразования типов
- •Глава 5. Наследование, виртуальные функции и полиморфизм
- •5.1 Наследование и спецификаторы доступа
- •5.1.1 Спецификаторы доступа
- •5.1.2 Спецификатор доступа при наследовании базового класса
- •5.1.3 Дополнительная спецификация доступа при наследовании
- •5.2 Конструкторы и деструкторы производных классов
- •5.3 Множественное наследование
- •5.4 Передача параметров в базовый класс
- •5.5 Указатели и ссылки на производные типы
- •5.6 Ссылки на производные классы
- •5.7 Виртуальные функции
- •5.8 Для чего нужны виртуальные функции?
- •5.9 Чисто виртуальные функции и абстрактные типы
- •5.10 Виртуальный базовый класс
- •5.11 Раннее и позднее связывание
- •Глава 6. Подсистема динамического выделения памяти
- •6.1 Введение в обработку исключений
- •6.1.1 Перехват всех исключений
- •6.2 Работа с памятью с помощью new и delete
- •6.3 Размещение объектов
- •6.4 Перегрузка new u delete
- •7.1.1 Потоки
- •7.3 Создание собственных операторов вставки и извлечения
- •7.3.1 Создание операторов вставки
- •7.3.2 Перегрузка операторов извлечения
- •7.4 Форматирование ввода/вывода
- •7.4.1 Форматирование с помощью функций-членов класса ios
- •7.4.2 Использование манипуляторов
- •7.5 Создание собственных функций-манипуляторов
- •7.5.1 Создание манипуляторов без параметров
- •7.5.2 Создание манипуляторов с параметрами
- •7.6 Файловый ввод/вывод
- •7.6.1 Открытие и закрытие файлов
- •7.6.2 Чтение и запись в текстовые файлы
- •7.6.3 Двоичный ввод/вывод
- •7.6.4 Определение конца файла
- •7.6.5 Произвольный доступ
- •Глава 8. Ввод/вывод в массивы
- •8.1 Классы ввода/вывода в массивы
- •8.2 Создание потока вывода
- •8.3 Ввод из массива
- •8.4 Использование функций-членов класса ios
- •8.5 Потоки ввода/вывода в массивы
- •8.6 Произвольный доступ в массив
- •8.7 Использование динамических массивов
- •8.8 Манипуляторы и ввод/вывод в массив
- •8.9 Собственные операторы извлечения и вставки
- •8.10 Форматирование на основе массивов
- •Глава 9. Шаблоны и библиотека stl
- •9.1 Функции-шаблоны
- •9.2 Функции с двумя типами-шаблонами
- •9.3 Ограничения на функции-шаблоны
- •9.4 Классы-шаблоны
- •9.5 Пример с двумя типами-шаблонами
- •9.6 Обзор библиотеки stl
- •9.7 Класс vector
- •9.7 Класс string
- •9.8 Класс list
8.6 Произвольный доступ в массив
Важно помнить, что все обычные операции ввода/вывода сохраняют свое значение для ввода/вывода в массивы. Сюда относится также произвольный доступ с использованием функций seekg() и seekp(). В качестве примера следующая программа получает восьмой символ в iostr и выводит его. (Выводится символ h.)
#include <strstrea.h>
#include <iostream.h>
int main()
{
char iostr[80];
strstream i(iostr, sizeof(iostr), ios::in | ios::out);
char ch;
i << "abcdefghijklmnopqrstuvwxyz";
i.seekg(7, ios::beg);
i >> ch;
cout << "Character at 7: " << ch << endl;
return 0;
}
Можно проводить поиск где угодно внутри массива, но нельзя осуществлять поиск за его пределами.
Также можно использовать функции tellg() и tellp().
8.7 Использование динамических массивов
В начале этой главы при связывании потока с массивом для вывода данных этот массив и его размер передавались конструктору класса ostrstream. Такой подход работает до тех пор, пока известно максимальное количество символов, которое потребуется вывести в массив. Что же делать, когда заранее неизвестно, насколько большой массив понадобится в дальнейшем? Решением этой проблемы служит вторая форма конструктора ostrtream, показанная ниже:
ostrtream();
При использовании этого конструктора ostrstream создает и поддерживает динамически выделяемый массив. Этот массив может расти по величине в соответствии с объемом данных, которые необходимо в нем хранить.
Для доступа к динамически выделяемому массиву следует использовать функцию str(). Она имеет следующий прототип:
char* str();
Эта функция «замораживает» массив и возвращает указатель на него. Как только массив заморожен, он не может снова использоваться для вывода данных. Поэтому не следует замораживать массив, пока продолжается запись в него символов.
Следующая программа использует динамический массив:
#include <strstrea.h>
#include <iostream.h>
int main()
{
char *p;
ostrstream outs; // динамическое размещение массива
outs << "I like C++ ";
outs << -10 << hex << " ";
outs.setf(ios::showbase);
outs << 100 << ends;
p = outs.str(); /* заморозка динамического буфера и возврат указателя на него */
cout << р;
delete p; //освобождение динамического буфера, созданного ostrstream()
return 0;
}
Как показывает эта программа, если заморозить массив, то придется самостоятельно освободить память при выходе из функции или программы. Однако если массив не заморожен, память будет освобождена автоматически при уничтожении потока ввода/вывода.
Можно также использовать динамические массивы с классом strstream, позволяющим как вводить, так и выводить данные в массив.
8.8 Манипуляторы и ввод/вывод в массив
Поскольку потоки для ввода/вывода в массив те же самые, что и другие потоки, то созданные вами манипуляторы могут использоваться также для ввода/вывода в массивы. Например, в прошлой главе был создан манипулятор для вывода setup(), который включал левое выравнивание и устанавливал ширину поля, равную 10, а в качестве символа заполнения определял знак $. Этот манипулятор может без изменений использоваться при выводе в массив, как показано ниже:
#include <strstrea.h>
#include <iostream.h>
#include <iomanip.h>
ostream& setup(ostream &stream)
{
stream.setf(ios::left);
stream << setw(10) << setfill('$');
return stream;
}
int main()
{
char str[80];
ostrstream outs(str, sizeof(str));
outs << setup << 99 << ends;
cout << str << endl;
return 0;
}