Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В примерах 14.25, 14.26 и 14.27 я использую функцию boost::serialization::make_nvpдля конструирования пар вида «имя-значение». В Boost.Serialization предусмотрен также макрос BOOST_SERIALIZATION_NVP, который позволяет выполнять сериализацию переменной, указывая ее имя. Первый компонент пары будет сконструирован автоматически препроцессором, используя оператор «стрингизации» (stringizing) #для преобразования макропараметров в строковые константы.
// То же самое, что и ar & make_nvp("name_", name_);
ar & BOOST_SERIALIZATION_NVP(name_);
В этих примерах я использую make_nvpвместо BOOST_SERIALIZATION_NVPдля лучшего контроля имен тегов, чтобы содержимое архива XML легче читалось.
В документации Boost.Serialization рекомендуется объявлять метод serialize()как закрытый ( private) для уменьшения ошибок пользователя, когда добавляется поддержка сериализации в классы, производные от других сериализуемых классов. Для того чтобы библиотека Boost.Serialization могла вызвать метод serialize()вашего класса, вам необходимо объявить дружественным класс boost:: serialization::access.
Наконец второй параметр метода serialize()в примерах 14.25 и 14.26 относится к той части Boost.Serialization, которая поддерживает управление версиями классов (class versioning) . Когда объект определенного класса первый раз сохраняется в архиве, вместе с ним сохраняется также его версия; когда выполняется десериализация экземпляра класса. Boost.Serialization передает сохраненную версию методу serializeв качестве второго аргумента. Эта информация может использоваться для специализации десериализации; например, serializeмог бы загружать переменную-член только в том случае, если записанная в архив версия класса, по крайней мере, не меньше версии класса, первым объявившим эту переменную. По умолчанию класс имеет версию 0. Для задания версии класса вызовите макрос BOOST_CLASS_VERSION, который определен в заголовочном файле boost/serialization/version.hpp , передавая в качестве аргументов имя и версию класса.
Глава 15
Разные функции
15.0. Введение
В этой главе рассматриваются некоторые аспекты C++, которые плохо вписываются в тематику любой другой главы: указатели функций и членов, константные переменные и функции- члены, независимые операторы (т.е. не члены класса) и несколько других тем.
15.1. Применение указателей функций для их обратного вызова
Планируется использование некоторой функции func1, которая на этапе выполнения должна вызывать другую функцию func2. Однако по той или иной причине нельзя внутри функции func1жестко закодировать имя функции func2. Возможно, имя функции func2неизвестно на этапе компиляции, или func1относится к программному интерфейсу независимого разработчика, и она не может быть изменена и перекомпилирована В любом случае вам придется воспользоваться функцией обратного вызова (callback function) .
При использовании указанных выше функций объявите func1с указателем на функцию в качестве своего аргумента и передайте ей адрес func2на этапе выполнения. Используйте typedef, чтобы программа легче читалась и отлаживалась. Пример 15.1 показывает, как можно реализовать функцию обратного вызова, используя указатель на функцию.
Пример 15.1. Функция обратного вызова
#include
// Пример функции обратного вызова
bool updateProgress(int pct) {
std::cout << pct << "% complete...\n";
return(true);
}
// Этот typedef делает программный код более понятным
typedef bool (*FuncPtrBoolInt)(int);
// Функция, которая выполняется достаточно длительное время
void longOperation(FuncPtrBoolInt f) {
for (long l=0; l < 100000000; l++)
if (l % 10000000 == 0)
f(l/1000000);
}
int main() {
longOperation(updateProgress); // нормально
}
В ситуации, которая показана в примере 15.1, применение указателя на функцию является хорошим решением, если UpdateProgressи longOperationничего не должны знать друг о друге. Например, функцию, которая обновляет индикатор состояния процесса в диалоговом окне пользовательского интерфейса (user interface — UI), в окне консольного режима или где-то еще, не заботит контекст, в котором она вызывается. Аналогично функция longOperationможет быть частью некоторого программного интерфейса загрузки данных, которого не заботит место вызова: из графического UI, из окна консольного режима или из фонового процесса.
Сначала потребуется определить сигнатуру функции, которую вы планируете вызывать, и создать для нее typedef. Оператор typedef— ваш помощник в тех случаях, когда приходится иметь дело с указателями функций, потому что они имеют не очень привлекательный синтаксис. Рассмотрим, как обычно объявляется такой указатель на примере переменной f, которая содержит адрес функции, принимающей единственный аргумент целого типа и возвращающей значения типа boolean. Это может выглядеть следующим образом
bool (*f)(int); // f - имя переменной
Вы можете справедливо возразить, что здесь нет ничего особенного и я просто излишне драматизирую ситуацию. Но что вы скажете, если требуется определить вектор vectorтаких указателей?
vector vf;
Или их массив?
bool (*af[10])(int);
Форма представления указателей на функции отличается от обычных переменных С++, которые обычно задаются в виде (квалифицированного) имени типа, за которым идет имя переменной. Поэтому они вносят путаницу при чтении программного кода.
Итак, в примере 15.1 я использовал следующий typedef.
typedef bool (*FuncPtrBoolInt)(int);
Сделав это, я могу свободно объявлять указатели функций с сигнатурой, возвращающей значение boolи принимающей единственный аргумент, как это я бы делал для параметра любого другого типа, например.
void longOperation(FuncPtrBoolInt f) { // ...
Теперь все, что надо сделать в longOperation, — это вызвать f, как если бы это была любая обычная функция.
f(l/1000000);
Таким образам, здесь fможет быть любой функцией, которая принимает аргумент целого типа и возвращает bool. Предположим, что в вызывающей функции longOperationне требуется обеспечивать продвижение индикатора состояния процесса. Тогда ей можно передать указатель на функцию без операций.
bool whoCares(int i) {return(true);}
//...
longOperation(whoCares);
Более важно то, что выбор функции, передаваемой longOperation, может осуществляться динамически на этапе выполнения.
15.2. Применение указателей для членов класса
Требуется обеспечить адресную ссылку на данное-член или на функцию-член.
Читать дальшеИнтервал:
Закладка: