
- •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. Ввод/вывод в массивы
В дополнение к вводу/выводу на консоль и в файлы, система ввода/вывода языка C++ позволяет осуществлять ввод/вывод в массивы. Ввод/вывод на основе массивов использует память в качестве устройства для ввода и вывода. Ввод/вывод на основе массивов осуществляется с помощью обычных потоков C++. Фактически вся представленная в предыдущей главе информация применима к вводу/выводу на основе массивов. Единственное, что отличает ввод/вывод на основе массивов, заключается в том, что связанным с потоком устройством служит память.
В некоторой литературе по C++ ввод/вывод на основе массивов (array-based I/O) называют также вводом/выводом в память (in-RAM I/O). Поскольку потоки способны форматировать информацию, то иногда ввод/вывод на основе массивов называют также форматированием в памяти (in-RAM formatting).
Вывод на основе массивов C++ подобен использованию функций sprintf() и sscanf() в языке С. В обоих случаях память используется в качестве устройства для ввода и вывода.
Для использования ввода/вывода на основе массивов необходимо включить в программу заголовочный файл strstrea.h.
8.1 Классы ввода/вывода в массивы
Классами для ввода/вывода на основе массивов являются istrstream, ostrstream и strstream. Эти классы используются для создания потоков ввода, вывода и ввода/вывода соответственно. Класс istrstream имеет в качестве базового класса istream. Класс ostrstream порожден от класса ostream, а класс strstream – от класса iostream. Поэтому все классы для вывода на основе массивов имеют доступ к тем же функциям, что и «нормальные» классы ввода/вывода.
8.2 Создание потока вывода
Для того, чтобы связать поток вывода с массивом, используется конструктор ostrstream:
ostrstream ostr(char *buf, int size, int mode=ios::out);
Здесь buf служит указателем на массив, который будет использоваться для хранения символов, записанных в поток ostr. Размер массива передается параметром size. По умолчанию поток открыт для нормального вывода, но, используя различные режимы, объединенные с помощью побитового ИЛИ, можно задать необходимый режим. Подробности обсуждались в предыдущей главе. Например, можно включить ios::app для того, чтобы выводимые данные были записаны в конец той информации, которая уже содержится в массиве.
После открытия потока вывода в массив, все выводимые в поток данные будут помещаться в массив. Однако никаких данных не будет записано за пределы массива. Попытка выполнить такую запись приведет к ошибке.
Ниже представлена простая программа, иллюстрирующая поток вывода в массив:
#include <strstrea.h>
#include <iostream.h>
int main()
{
char str[80];
int a = 10;
ostrstream outs(str, sizeof(str));
outs << "Hello there " << a+44 << hex << " ";
outs.setf(ios::showbase);
outs << 100 << ends;
cout << str; // вывод строки на консоль
return 0;
}
Эта программа выводит текст «Hello there 54 0x64». Надо иметь в виду, что outs является потоком, подобно любому другому потоку, и поэтому он имеет те же возможности, что и любой из рассмотренных выше потоков. Единственная разница заключается в том, что поток связан с памятью. Поскольку outs является потоком, то можно использовать манипуляторы наподобие hex или ends. Функции-члены класса ostream, такие как setf(), также сохраняют свое значение.
Если необходимо, чтобы массив для хранения данных завершался нулевым символом, необходимо явным образом записать данный нулевой символ. В предыдущей программе манипулятор ends использовался для создания строк, оканчивающихся нулем, но можно также использовать ‘\0’.
Если нет полной уверенности в том, что происходит в предыдущей программе, то надо сравнить ее со следующей программой на языке С. Эта программа в функциональном отношении эквивалентна предыдущей С++-версии. Отличие заключается в том, что в ней для вывода в массив используется функция sprinf().
#include <stdio.h>
int main()
{
char str[80];
int a = 10;
sprintf(str, "Hello there %d %#x", a+44, 100);
printf (str);
return 0;
}
Можно определить количество символов в массиве с помощью вызова функции-члена pcount(). Она имеет следующий прототип:
int pcount();
Число, возвращаемое функцией pcount() также включает нулевой символ, если он существует.
Следующая программа иллюстрирует использование функции pcount(). Она сообщает, что в потоке outs содержится 17 символов — 16 букв и нулевой символ.
#include <strstrea.h>
#include <iostream.h>
int main()
{
char str[80];
ostrstream outs(str, sizeof(str));
outs << "Hello " << 34 << " " << 1234.23;
outs << ends; // завершение нулем
cout << outs.pcount(); // вывод числа символов в потоке outs
cout << " " << str;
return 0;
}