Строковые потоки и буферы

Содержание

Слайд 2

Функции позиционирования в потоках данных С++ Позиционирование чтения и записи выполняется

Функции позиционирования в потоках данных С++

Позиционирование чтения и записи выполняется отдельными

функциями (суффикс «g» означает «get», а суффикс «p» - «put»). Не все потоковые классы поддерживают позиционирование! Например, для потоков данных cin, cout и сеrr позиционирование не определено. Операции файлового позиционирования определяются в базовых классах, потому что обычно используются ссылки на объекты типов istream и ostream. Функции seekg() и seekp() могут вызы-ваться для абсолютных или относительных позиций. Функции tellg() и tellp() возвращают абсолютную позицию в виде значения типа pos_type. Это значе-ние не является целым числом или индексом, задающим позицию символа, поскольку логическая позиция может отличаться от фактической.
Слайд 3

Что такое позиция? Что есть тип pos_type? Стандартная библиотека С++ определяет

Что такое позиция?

Что есть тип pos_type? Стандартная библиотека С++ определяет глобальный

класс шаблона fpos<> для представления позиций в файлах. На базе класса fpos< > определяются типы streampos (для потоков данных char) и wstreampos (для потоков данных wchar_t). Эти типы используются для определения pos_type соответствующих классов трактовок. Наконец, переменная типа pos_type класса трактовок требуется для определения типа pos_type соответствующих потоковых классов. Следовательно, позиции в потоке данных также могут представляться типом streampos, но использовать
типы long и unsigned long было бы неправильно, потому что streampos не является целочисленным типом (а точнее, перестал им быть!). Пример:
// Сохранение текущей позиции
std::ios::pos_type pos = file.tellg();
// Переход к позиции. хранящейся в pos
file.seekg(pos);
Следующие объявления эквивалентны:
std::ios::pos_type pos;
std::streamppos pos;
Слайд 4

Что такое относительная позиция? В версиях с относительным позиционированием смещение задается

Что такое относительная позиция?

В версиях с относительным позиционированием смещение задается по

отношению к трем позициям, которые описываются соответствующими константами, определенными в классе ios_base и относящихся к типу seekdir.

Смещение относится к типу off_type, который представляет собой косвенное определение для streamoff. По аналогии с pos_type тип streamoff используется для определения off_type в классе трактовок и в потоковых классах. Тем не менее streamoff является целым знаковым типом, поэтому смещение в потоке данных может задаваться целым числом. Пример:
file.seekg (0, std::ios::beg); // Позиционирование в начало файла
file.seekg (20, std::ios::cur); // Позиционирование на 20 символов вперед
file.seekg (-10, std::ios::end); // Позиционирование на 10 символов от конца

Слайд 5

Пример позиционирования // Заголовочные файлы для ввода-вывода #include #include void printFileTwice

Пример позиционирования

// Заголовочные файлы для ввода-вывода
#include
#include
void printFileTwice (const char*

filename)
{
std::ifstream file(filename); // Открытие файла
std::cout << file.rdbuf(); // Первый вывод содержимого
file.seekg(0); // Возврат к началу файла
std::cout << file.rdbuf(); // Второй вывод содержимого
}
void main (int argc, char* argv[])
{
// Двукратный вывод всех файлов, переданных в командной строке
for (int i=1; i printFileTwice(argv[i]);
}
}
Слайд 6

Перенаправление потоков данных Перенаправление потока данных осуществляется назначением потокового буфера. В

Перенаправление потоков данных

Перенаправление потока данных осуществляется назначением потокового буфера.
В механизме назначения

потоковых буферов перенаправление потоков данных находится под управлением программы, операционная система здесь не
участвует.
В результате выполнения следующего фрагмента данные, отправленные в поток данных cout, будут передаваться не в стандартный выходной канал, а в файл cout.txt:
std::ofstream filе ("cout.txt");
std::cout.rdbuf (file.rdbuf());
Для передачи всей форматной информации между потоками данных можно воспользоваться функцией copyfmt():
std::ofstream file("cout.txt");
file.copyfmt (std::cout);
std::cout.rdbuf (file.rdbuf());
Слайд 7

Перенаправление потоков данных - пример #include #include using namespace std; void

Перенаправление потоков данных - пример

#include
#include
using namespace std;
void redirect(ostream&);
int main()
{

cout << "the first row" << endl;
redirect (cout);
cout << "the last row" << endl;
}

Продолжение…

Слайд 8

Перенаправление потоков данных - пример void redirect (ostream& strm) { ofstream

Перенаправление потоков данных - пример

void redirect (ostream& strm)
{
ofstream file("redirect.txt");

streambuf* strm_buffer = strm.rdbuf(); // Сохранение выходного буфера потока
strm.rdbuf (file.rdbuf()); // Перенаправление вывода в файл
file << "оne row for the file" << endl;
strm << "оnе row for the stream" << endl;
strm.rdbuf (strm_buffer); // Восстановление старого выходного буфера
} // Автоматическое закрытие файла и буфера

Результат выполнения программы выглядит так:
the first row
the last row

Содержимое файла redirect.txt:
оnе row for the file
оnе row for the stream

Слайд 9

Потоки чтения и записи Обычно файл открывается для чтения/записи при помощи

Потоки чтения и записи

Обычно файл открывается для чтения/записи при помощи класса

fstream:
std::fstream file ("example.txt", std::ios::in | std::ios::out);
Можно использовать два разных потоковых объекта, по одному для чтения и записи.
std::ofstream out("example.txt", ios::in | ios::out);
std::istream in(out.rdbuf());
Объявление out открывает файл. Объявление in использует потоковый буфер out для чтения из него. Обратите внимание: поток данных out должен открываться для чтения и записи. Если открыть его только для записи, чтение из потока данных приведет к непредсказуемым последствиям. Также обратите внимание на то, что in определяется не с типом ifstream, а только с типом istream. Файл уже открыт, и у него имеется соответствующий потоковый буфер. Все, что требуется, - это второй потоковый объект. Как и в предыдущих примерах, файл закрывается при уничтожении объекта файлового потока данных.
Слайд 10

Потоки чтения и записи Еще вариант - создать буфер файлового потока

Потоки чтения и записи

Еще вариант - создать буфер файлового потока данных

и назначить его обоим потоковым объектам. Решение выглядит так:
std::filebuf buffer;
std::ostream out(&buffer);
std::istream in(&buffer);
buffer.open("example.txt", std::ios::in | std::ios::out);
Объект filebuf является обычной специализацией класса basic_filebuf<> для типа char.
Класс определяет потоковый буфер, используемый файловыми потоками данных.
Далее рассмотрим пример, в котором с помощью цикла в файл выводится четыре строки.
После каждой операции вывода все содержимое файла записывается в стандартный выходной поток данных.
Слайд 11

Потоки чтения и записи - пример #include #include using namespace std;

Потоки чтения и записи - пример

#include
#include
using namespace std;
void main()
{

// Открытие файла "example.dat" для чтения и записи
filebuf buffer;
ostream output(&buffer);
istream input(&buffer);
buffer.open ("example.dat", ios::in | ios::out | ios::trunc);
for (int i=1; i<=4; i++) {
output << i << ". line" << endl; // Запись одной строки
// Вывод всего содержимого файла
input.seekg(0); // Позиционирование в начало
char c;
while (input.get(c)) { cout.put(c); }
cout << endl;
input.clear ( ); // Сброс флагов eofbit и failbit
}
}

Результат:
1. line
1. line
2. Line
1. line
2. line
З. line
1. line
2. line
З. line
4. line

Слайд 12

Потоки чтения и записи - пример Хотя для чтения и записи

Потоки чтения и записи - пример

Хотя для чтения и записи используются

два разных объекта потоков данных, позиции чтения и записи тесно связаны между собой. Функции seekg() и seekp() вызывают одну и ту же функцию потокового буфера!
Следовательно, для того чтобы вывести все содержимое файла, необходимо всегда устанавливать позицию чтения в начало файла. После вывода всего содержимого файла позиция чтения/записи снова перемещается в конец файла для присоединения новых строк.
Операции чтения и записи с одним файлом должны разделяться операцией позиционирования (кроме выхода за конец файла во время чтения). Пропуск операции позиционирования приведет к искажению содержимого файла или еще более фатальным ошибкам.
Вместо последовательной обработки символов все содержимое файла можно вывести одной командой, для чего оператору << передается указатель на потоковый буфер:
std::cout << input.rdbuf();
Слайд 13

Потоковые классы для работы со строками Механизм потоковых классов также может

Потоковые классы для работы со строками

Механизм потоковых классов также может использоваться

для чтения или записи в строки. У строковых потоков данных имеется буфер, но нет канала ввода-вывода. Для работы с буфером/строкой используются специальные функции.
Основная область применения строковых потоков данных - обработка вводимых/выводимых данных независимо от фактического механизма ввода-вывода. Например, выводимый текст можно отформатировать в строке и передать в выходной канал позднее. Другой вариант - ввод данных по строкам и обработка строк с использованием строковых потоков данных.
Раньше в классах строковых потоков данных для представления строк использовался тип char*. В современной библиотеке для представления строк используется тип string (или в общем случае - basic_string<>.
Слайд 14

Классы строковых потоков данных Для строк определены следующие потоковые классы, которые

Классы строковых потоков данных

Для строк определены следующие потоковые классы, которые явля-ются

аналогами соответствующих классов файловых потоков данных:
шаблон basic_istringstream со специализациями istringstream и wistringstream для чтения из строк («строковыЙ входной поток данных»);
шаблон basic_ostringstream со специализациями ostringstream и wostгingstream для записи в строки («строковый выходной поток данных»);
шаблон basic_stringstream со специализациями stringstream и wstringstream для чтения и записи в строки;
шаблон basic_stringbuf<> со специализациями stringbuf и wstringbuf используется другими классами строковых потоков данных для реальных чтения и записи символов.
Слайд 15

. Иерархия классов cтроковых потоков данных ios_base basic_streambuf streambuf / wstreambuf

.

Иерархия классов cтроковых потоков данных

ios_base

basic_streambuf<>
streambuf / wstreambuf

basic_ios<>
ios / wios

basic_istream<> istrеаm /

wistream

basic_ostream<> ostrеаm / wostream

basic_iostream<>
iostream / wiostream

(virtual)

basic_stringbuf<>
stringbuf / wstringbuf

basic_istringstream<> istringstrеаm/wistringstream

basic_ostringstream<> ostringstrеаm/wostringstream

basic_stringstream<>
stringstream / wstringstream

Слайд 16

Основные операции со строковыми потоками данных Основная операция реализуется функциями: str()

Основные операции со строковыми потоками данных

Основная операция реализуется функциями:
str() - возвращает

буфер в виде строки;
str(string) - присваивает string содержимое буфера.
Например
cout << os.str() << endl;

Строковые входные потоки данных в основном используются для формати-рованного чтения из существующих строк. часто бывает проще читать данные по строкам и затем анализировать каждую строку в отдельности.
В следующем фрагменте из строки s читается целое число х, равное 3, и вещественное число f, равное 0.7:
int х;
float f;
std::string s = "3.7";
std::istringstream is(s);
is >> х >> f;

Слайд 17

Операции со строковыми потоками данных При создании строковых потоков данных могут

Операции со строковыми потоками данных

При создании строковых потоков данных могут задаваться

флаги режима открытия файла и/или существующие строки. С флагами ios::app и ios::ate символы, записанные в строковый поток данных, присоединяются к существующей строке:
#include
std::string s;
std::ostringstream os (s, ios::ate);
os << 77 << std::hex << 77;
Однако строка, возвращаемая функцией str(), представляет собой копию строки s с присоединенными значениями 77 в десятичном и шестнадцатеричном виде.
При этом сама строка s остается неизменной.
Слайд 18

Правила построения пользовательских операторов ввода-вывода Правила, которые должны соблюдаться в пользовательских

Правила построения пользовательских операторов ввода-вывода

Правила, которые должны соблюдаться в пользовательских реализациях операторов

ввода-вывода. Они продиктованы типичным поведением стандартных операторов.
Выходной формат должен допускать определение оператора ввода, читающего данные без потери информации. В некоторых случаях - особенно для строк эта задача практически невыполнима из-за проблем с пробелами. Пробел внутри строки невозможно отличить от пробела, разделяющего две строки.
При вводе-выводе должна учитываться текущая форматная спецификация потока данных. Прежде всего это относится к ширине поля при выводе.
При возникновении ошибок должен быть установлен соответствующий флаг состояния.
Ошибки не должны изменять состояние объекта. Если оператор читает несколько объектов данных, промежуточные результаты сохраняются во временных объектах до окончательного принятия значения.
Вывод не должен завершаться символом новой строки, в основном из-за того, что это не позволит вывести другие объекты в той же строке.
При обнаружении ошибки форматирования следует по возможности прекратить чтение.
Даже слишком большие данные должны читаться полностью. После чтения следует установить соответствующий флаг ошибки, а возвращаемое значение должно содержать полезную информацию (например, максимальное допустимое значение).
Слайд 19

Классы потоковых буферов – вывод символов Потоки данных не выполняют непосредственные

Классы потоковых буферов – вывод символов

Потоки данных не выполняют непосредственные операции

чтения и записи, а поручают их потоковым буферам.
С точки зрения пользователя потокового буфера, класс basic_streambuf представляет собой нечто, принимающее и отправляющее символы, где traits_type определение типа в классе basic_streambuf.
Открытые функции вывода символов:
sputc(c) - выводит символ с в потоковый буфер;
sputn(s, n) - выводит n символов из последовательности s в потоковый буфер.
Функция sputc() возвращает traits_type::eof() в случае ошибки.
Функция sputn() выводит количество символов, заданное вторым аргументом, если только выводу не помешают недостаточные размеры строкового буфера. Символы завершения строк при выводе не учитываются. Функция возвращает количество выведенных символов.
Слайд 20

Классы потоковых буферов – ввод символов При вводе иногда требуется узнать

Классы потоковых буферов – ввод символов

При вводе иногда требуется узнать символ

без его извлечения из буфера. Кроме того, желательно предусмотреть возможность возврата символов в потоковый буфер. Соответствующие функции поддерживаются классами потоковых буферов.
Слайд 21

Потоковые буфера – ввод символов Функция in_avail() проверяет минимальное количество доступных

Потоковые буфера – ввод символов

Функция in_avail() проверяет минимальное количество доступных символов.

Например, с ее помощью можно убедиться в том, что чтение не будет заблокиро-вано при вводе с клавиатуры. С другой стороны, количество доступных симво-лов может быть больше значения, возвращаемого этой функцией.
Пока потоковый буфер не достигнет конца потока данных, один из символов считается «текущим». Функция sgetc() используется для получения текущего символа без перемещения к следующему символу.
Функция sbumpc() читает текущий символ и переходит к следующему, который становится текущим.
Функция snextc(), переходит к следующему символу и читает новый текущий символ. Для обозначения неудачи все три функции возвращают traits_type::eof().
Функция sgetn() читает в буфер последовательность символов, максимальная длина которой передается в аргументе. Функция возвращает количество прочитанных символов.
Функции sputbackc() и sungetc() возвращаются на одну позицию в потоке данных, вследствие чего текущим становится предыдущий символ. Функция sputbackc() может использоваться для замены предыдущего символа другим символом. При вызове этих функций необходимо соблюдать осторожность: нередко возврат ограничивается всего одним символом.
Слайд 22

Потоковые буфера – другие функции Отдельная группа функций используется для подключения

Потоковые буфера – другие функции

Отдельная группа функций используется для подключения объекта

локального контекста, для смены позиции и управления буферизацией.

Функция pubimbue() подключает новый объект локального контекста
к потоковому буферу и возвращает ранее установленный объект локального
контекста. Функция getloc() возвращает текущий объект локального контекста.

Слайд 23

Потоковые буфера – другие функции - пояснения Функция pubsetbuf() позволяет в

Потоковые буфера – другие функции - пояснения

Функция pubsetbuf() позволяет в определенной

степени управлять стратегией буферизации потоковых буферов.
Функции pubseekoff() и pubseekpos() используются для управления текущей позицией чтения и/или записи. Позиция зависит от последнего аргумента, который относится к типу ios_base: :openmode и по умолчанию равен ios_base::in | ios_base::out. При установленном флаге ios_base::in изменяется позиция чтения, а при установленном флаге ios_base::out - позиция записи.
Функция pubseekpos() перемещает поток данных в абсолютную позицию, заданную первым аргументом, тогда как функция pubseekoff() использует смещение, заданное по отношению к другой позиции. Смещение передается в первом аргументе. Позиция, по отношению к которой задается смещение, передается во втором аргументе и может быть равна ios_base::cur, ios_base::beg или ios_base::end.
Обе функции возвращают новую текущую позицию или признак недействи-тельной позиции. Чтобы обнаружить недействительную позицию, следует сравнить результат с объектом pos_type(off_type(-1)).
Текущая позиция потока возвращается функцией pubseekoff():
sbuf.pubseekoff(0, std::ios::cur);
Слайд 24

Синхронизация со стандартными потоками данных С По умолчанию восемь стандартных потоков

Синхронизация со стандартными потоками данных С

По умолчанию восемь стандартных потоков данных

С++ (четыре символь-ных потока с однобайтовой кодировкой cin, cout, cerr и clog, а также четыре их аналога с расширенной кодировкой) синхронизируются с соответствующи-ми каналами из стандартной библиотеки С (stdin, stdout и stderr).
По умолчанию clog и wclog используют тот же потоковый буфер, что и cerr и wcerr соответственно. Таким образом, по умолчанию они синхронизи-руются с stderr, хотя в стандартной библиотеке С у этих потоков данных нет прямых аналогов.
В зависимости от реализации синхронизация может приводить к лишним затратам. Например, если стандартные потоки данных С++ реализованы с использованием стандартных файлов С, это фактически подавляет буфериза-цию соответствующих потоковых буферов. Однако буферизация необходима для выполнения некоторых оптимизаций, особенно для форматированного чтения. Чтобы программист мог переключиться на нужную реализацию, в классе ios_base определена статическая функция:
sync_with_stdio() - возвращает информацию о том, синхронизируются ли стандартные объекты потоков данных со стандартными потоками данных С;
sync_with_stdio(false) - запрещает синхронизацию потоков данных С++ и С (при условии, что функция была вызвана до первой операции ввода-вывода).
Слайд 25

Непосредcтвенная работа с потоковыми буферами Все функции классов basic_istream и basic_ostream,

Непосредcтвенная работа с потоковыми буферами

Все функции классов basic_istream и basic_ostream, выполняющие

чтение или запись символов, работают по одной схеме: сначала конструируется соответствующий объект sentry, а затем выполняется операция. Конструирование объекта sentry приводит к очистке буферов возможных связанных объектов, игнорированию пропусков (только при вводе) и выполнению операций, специфических для конкретных реализаций, например операций блокировки файлов в средах с параллельным функционированием нескольких потоков выполнения (threads), то есть в многопоточных средах.
При неформатированном вводе-выводе многие операции потоков данных все равно бесполезны, разве что операция блокировки может пригодиться при работе с потоками в средах с параллельным функционированием нескольких потоков выполнения (поскольку в С++ проблемы многопоточности не решаются).
Следовательно, при неформатированном вводе-выводе прямая работа с потоковыми буферами обычно более эффективна.
Слайд 26

Непосредcтвенная работа с потоковыми буферами ( Для этого можно определить для

Непосредcтвенная работа с потоковыми буферами (<<)

Для этого можно определить для потоковых

буферов операторы << и >>.
(1) При получении указателя на потоковый буфер оператор << выводит все накопленные данные. Это самый быстрый способ копирования файлов с использованием потоков данных С++.
Пример:
#include
int main ()
{ // Копирование стандартного ввода в стандартный вывод
std::cout << std::cin.rdbuf();
}
В этом фрагменте функция rdbuf() возвращает буфер потока cin. Следовательно, программа копирует весь стандартный входной поток данных в стандартный выходной поток.
Слайд 27

Непосредcтвенная работа с потоковыми буферами (>>) При получении указателя на потоковый

Непосредcтвенная работа с потоковыми буферами (>>)

При получении указателя на потоковый буфер

оператор >> выполняет прямое чтение данных. Например, копирование стандартного входного потока данных в стандартный выходной поток также может выполняться следующим образом:
Пример:
#include
int main ()
{
// Копирование стандартного ввода в стандартный вывод
std::cin >> std::noskipws >> std::cout.rdbuf();
}
Обратите внимание на сброс флага skipws. В противном случае будут проигнорированы начальные пропуски во входных данных.
Слайд 28

Интернационализация С развитием глобального рынка интернaционализация стала играть более важную роль

Интернационализация

С развитием глобального рынка интернaционализация стала играть более важную роль

в разработке программного обеспечения. По этой причине в стандартную библиотеку С++ были включены средства написания локализо-ванного кода. В основном они связаны с вводом-выводом и обработкой строк.

Стандартная библиотека С++ предоставляет общие средства поддержки
национальных стандартов без привязки к конкретным системам и правилам.

При интернационализации программ следует учесть 2 момента:

Разные кодировки символов обладают разными свойствами. Для работы с ними необходимы гибкие решения практических вопросов.
Пользователь рассчитывает, что применяемая им программа соответствует национальным и культурным стандартам.

Основной механизм интернационализации основан на использовании о6ъекта локального контекста. Локальный контекст (locale) отражает расширяемый набор правил, адаптируемых для конкретных национальных стандартов.

Слайд 29

Поддержка разных кодировок символов Существуют два основных принципа определения кодировок, содержащих

Поддержка разных кодировок символов

Существуют два основных принципа определения кодировок, содержащих более

256 символов: много6айтовое и расширенное представления.

В много6айтовых кодировках символы представляются переменным количеством байтов. За однобайтовым символом (например, символом из кодировки ISO Latin-1) может следовать трехбайтовый символ (японский иероглиф).
В расширенных кодировках символ всегда представляется постоянным количеством байтов независимо от его типа. В типичных кодировках символ представляется величиной 2 или 4 байта.

Многобайтовое представление более компактно по сравнению с расширенным, поэтому для хранения данных вне программ обычно применяется многобайтовое представление. И наоборот, с символами фиксированного размера гораздо удобнее работать, поэтому в программах обычно используется расширенное представление.

Преобразование между кодировками символов осуществляется при помощи
шаблона codecvt<>. Этот класс используется в основном классом
basic_filebuf<> для преобразования между внутренними и внешними
представлениями.

Слайд 30

Трактовки символов Различия в кодировках существенны для обработки строк и ввода-вывода.

Трактовки символов

Различия в кодировках существенны для обработки строк и ввода-вывода.
Строковые

и потоковые классы специализируются встроенными типами char и wchar_t. Интерфейс встроенных типов должен оставаться неизменным, поэтому информация о разных аспектах представления символов выделяется в отдельный класс - так называемый класс трактовок символов. Он передается строковым и потоковым классам в аргументе шаблона.
По умолчанию в этом аргументе передается класс char_traits, параметризованный по аргументу, определяющему тип символов строки или потока данных.

Трактовки символов указываются в классе char_traits<>, который определяется в заголовочном файле и параметризуется по конкретному типу символов:
namespace std {
template
struct char_traits {
. . .
};
}

Классы трактовок определяют все основные свойства типа символов и операции, необходимые для реализации строк и потоков данных как статических
компонентов.

Слайд 31

Классы трактовки символов - функции

Классы трактовки символов - функции


Слайд 32

Классы трактовки символов – функции (дальше)

Классы трактовки символов – функции (дальше)

Слайд 33

Концепция локального контекста Распространенный подход к интернационализации основан на использовании специальных

Концепция локального контекста

Распространенный подход к интернационализации основан на использовании специальных сред,

называемых локальными контекстами (locale) и инкапсулиру-ющих национальные или культурные стандарты.
В отношении интернационализации локальный контекст представляет собой набор параметров и функций, обеспечивающих поддержку национальных или культурных стандартов. В зависимости от локального контекста выбираются разные форматы вещественных чисел, дат, денежных сумм и т. д.
Обычно локальный контекст определяется строкой в формате
язык[зона[.код]]
Здесь язык - обозначение языка (например, английский или немецкий), а зона - страна, географический регион или культура, в которой используется этот язык. Квалификатор код определяет кодировку символов.
locale langLocale(""); - создание локального контекста.
Пустая строка вместо имени локального контекста имеет особый смысл: она
обозначает локальный контекст по умолчанию для окружения пользователя . Этот локальный контекст связывается со стандартным входным потоком данных командой: cout.imbue(langLocale);
Слайд 34

Фацеты На функциональном уровне локальный контекст делится на несколько специальных объектов.

Фацеты

На функциональном уровне локальный контекст делится на несколько специальных объектов. Объект,

обеспечивающий работу некоторого аспекта интернационализации, называется фацетом. Это означает, что объект локального контекста может рассматриваться как контейнер для различных фацетов. Для обращения к некоторому аспекту локального контекста тип соответствующего фацета передается в аргументе шаблонной функции use_facet(). Например, следующее выражение обращается к фацету типа numpunct для типа символов char объекта локального контекста loc:
std::use_facet >(loc)
Каждый тип фацета определяется в виде класса, предоставляющего определенные сервисы. Например, тип фацета numpunct предоставляет сервис форматирования числовых и логических величин. Так, следующее выражение возвращает строку, используемую для представления true в локальном контексте loc:
std::use_facet >(loc).truename()
Фацеты делятся на категории, используемые некоторыми конструкторами для создания новых объектов локальных контекстов на основании комбинации других объектов.
Слайд 35

Категории фацетов стандартной библиотеки С++

Категории фацетов стандартной библиотеки С++

Слайд 36

Фацеты - использование Определение собственных версий фацетов позволяет создавать специализированные локальные

Фацеты - использование

Определение собственных версий фацетов позволяет создавать специализированные локальные контексты.

В следующем примере показано, как определяется фацет для использования русских строковых представлений логических величин:
class RusBoolNames : public std::numpunct_byname {
public:
RusBoolNames (const char *name): std::numpunct_byname(name) {}
protected:
virtual std::string do_truename () const {return "истина"; }
virtual std::string do_falsename () const {return "ложь"; }
};
Чтобы использовать этот фацет в локальном контексте, необходимо создать новый объект локального контекста при помощи специального конструктора класса locale. В первом аргументе этого конструктора передается объект локального контекста, а во втором - указатель на фацет. Созданный локальный контекст идентичен первому аргументу во всем, кроме фацета, переданного во втором аргументе. Заданный фацет устанавливается в созданном объекте контекста после копирования первого аргумента:
std::locale loc (std::locale(" " ). new RusBoolNames(" " );
Слайд 37

Тесты … Вопрос: Какой вывод будет у этой программы? #include int

Тесты …

Вопрос: Какой вывод будет у этой программы?

#include
int main()


{
std::cout << ++static_cast(*(new int(5)));
}

Варианты ответа:
(1) 6
5
0
Результат не определён
Ошибка компиляции

Слайд 38

Тесты … Вопрос: Какой вывод будет у этой программы? #include int

Тесты …

Вопрос: Какой вывод будет у этой программы?

#include
int main()


{
std::cout << ++static_cast(*(new int(5)));
}

Варианты ответа:
(1) 6
5
0
Результат не определён
Ошибка компиляции

Слайд 39

Тесты … Вопрос: Что произойдет при попытке скомпилировать и исполнить нижеприведенный

Тесты …

Вопрос: Что произойдет при попытке скомпилировать и исполнить нижеприведенный код?

class

CBase {
public:
/*...*/
};
typedef CBase * LPBASE;
void process( const LPBASE pBase)
{
/*...*/ }
class CDerived : public CBase
{
/*...*/ };
int main() {
CDerived d;
const CDerived* pd = &d;
process(pd);
return 0;
}

Варианты ответа:
Ошибка компиляции
Ошибка исполнения
Undefined behaviour
Код не содержит ошибок