Виталий Ткаченко - Обратные вызовы в C++

Тут можно читать онлайн Виталий Ткаченко - Обратные вызовы в C++ - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство Array SelfPub.ru, год 2021. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Виталий Ткаченко - Обратные вызовы в C++ краткое содержание

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

Обратные вызовы в C++ - читать онлайн бесплатно полную версию (весь текст целиком)

Обратные вызовы в C++ - читать книгу онлайн бесплатно, автор Виталий Ткаченко
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать
Листинг 100. Класс для анализа минимального и максимального значения (SensorControl.cpp)

class FindMinMaxValue

{

public:

enum MinMaxSign { MIN_VALUE = 0, MAX_VALUE = 1 }; // (1)

FindMinMaxValue(SensorNumber first, SensorNumber last, MinMaxSign sign) : // (2)

sign_(sign), first_(first), last_(last), count_(0)

{

if (sign == MIN_VALUE)

{

result_ = std::numeric_limits::max(); // (3)

}

else

{

result_ = std::numeric_limits::min(); // (4)

}

arrayFunMinMax_[MIN_VALUE] = &FindMinMaxValue::CompareMin; // (5)

arrayFunMinMax_[MAX_VALUE] = &FindMinMaxValue::CompareMax; // (6)

}

void operator()(SensorNumber number, SensorPointer sensor) // (7)

{

if ( sensor->isOperable() && (number >= first_ && number <= last_) ) // (8)

{

(this->*arrayFunMinMax_[sign_])(sensor->getValue()); // (9)

count_++; // (10)

}

}

SensorValue result() { return result_; } // (11)

size_t count() { return count_; } // (12)

private:

SensorNumber first; // (13)

SensorNumber last; // (14)

MinMaxSign sign; // (15)

SensorValue result; // (16)

size_t count; // (17)

using FunMinMax = void (FindMinMaxValue::*)(SensorValue value); // (18)

void CompareMin(SensorValue value) // (19)

{

if (result_ > value)

{

result_ = value;

}

}

void CompareMax(SensorValue value) // (20)

{

if (result_ < value)

{

result_ = value;

}

}

FunMinMax arrayFunMinMax_[2]; // (21)

};

В строке 2 объявлен конструктор, который принимает на вход следующие параметры: минимальное значение диапазона номеров; максимальное значение диапазона номеров; параметр, указывающий, что необходим поиск минимального либо максимального значения. В конструкторе инициализируются переменные класса: минимальное значение диапазона (объявлено в строке 13); максимальное значение диапазона (объявлено в 14); параметр для поиска (объявлено в 15); итоговый результат (объявлено в 16); количество датчиков, которые участвовали в поиске (объявлено в 17). В зависимости от переданного параметра начальный результат инициализируется соответственно максимальным либо минимальным значением (строки 3 и 4). Кроме того, инициализируется массив указателей на функцию (строки 5 и 6, объявление в 21). Данные функции предназначены для сравнения и запоминания максимального либо минимального значений (объявлены в 19 и 20).

Анализ очередного значения происходит в перегруженном операторе 7. На вход подаются номер датчика и указатель на датчик. Если датчик работоспособный и его номер попадает в заданный диапазон номеров (строка 8), то в зависимости от параметра поиска через указатель вызывается соответствующая функция для анализа (строка 9), а также увеличивается счетчик просмотренных датчиков (строка 10). Функции 11 и 12 возвращают итоговые результаты.

Итак, класс для анализа готов. Теперь можно вызвать метод для итерации по элементам контейнера, и в качестве обратного вызова передать экземпляр соответствующего вспомогательного класса. Метод будет вызывать перегруженный оператор, и таким образом, мы узнаем минимальное либо максимальное значение (Листинг 101).

Листинг 101. Поиск минимального и максимального значений (SensorControl.cpp)

SensorValue SensorControl::getMinValue(SensorNumber first, SensorNumber last)

{

checkInitialize();

FindMinMaxValue fmv(first, last, FindMinMaxValue::MIN_VALUE);

sensorContainer_->forEachSensor(fmv);

return fmv.result();

}

SensorValue SensorControl::getMaxValue(SensorNumber first, SensorNumber last)

{

checkInitialize();

FindMinMaxValue fmv(first, last, FindMinMaxValue::MAX_VALUE);

sensorContainer_->forEachSensor(fmv);

return fmv.result();

}

6.3. Разработка системного API

6.3.1. API как оболочка

Уже после того, как классы модуля были разработаны, протестированы и начали использоваться в системе, появилось новое требование – ввести поддержку системного API. Как известно, в интерфейсах системных API можно использовать только внешние функции и простые структуры данных в стиле C; классы и другие специфические конструкции C++ использовать нельзя (см. п. 1.4.2). Так что же, все теперь придется переписывать? Можно предложить следующее решение: использовать интерфейс API как оболочку для вызова методов класса. Концептуальный пример приведен в Листинг 102.

Листинг 102. Концептуальный пример реализации API как оболочки

using ControlPointer = std::unique_ptr;

ControlPointer g_SensorControl(sensor::ISensorControl::createControl());

void initialize () // This function is declared in the header file as part of API interface

{

g_SensorControl->initialize();

}

Однако не все так просто, перед нами встают следующие проблемы.

1. В исходной реализации мы использовали специфические типы C++, такие, как std::function, smart pointers и т. п., что не допускается в интерфейсах системных API. Какие типы использовать взамен?

2. Для обработки ошибок в исходной реализации мы использовали исключения. Как сейчас обрабатывать ошибки, ведь в интерфейсах API исключения недопустимы?

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

4. В исходной реализации драйвер настраивался путем создания нового класса и передаче его в интерфейсный класс. Как теперь настраивать драйвер, если в интерфейсах API нельзя использовать классы?

5. Как организовать обратные вызовы?

Рассмотрим, как эти проблемы можно решить.

6.3.2. Объявления типов

В исходной реализации общие типы объявлены в SensorDef.h , но мы не можем просто перенести их в интерфейс API из-за использования специфических конструкций С++. Поэтому нам придется повторить эти объявления в стиле C с использованием простых типов, которые можно будет использовать в интерфейсных функциях. Объявления представлены в Листинг 103.

Листинг 103. Объявления типов для интерфейса API (SensorLib.h)

#ifdef _WINDOWS // (1)

#ifdef LIB_EXPORTS

#define LIB_API __declspec(dllexport)

#else

#define LIB_API __declspec(dllimport)

#endif

#else

#define LIB_API

#endif

typedef uint32_t SensorNumber; // (2)

typedef double SensorValue; // (3)

typedef uint32_t CheckAlertTimeout; // (4)

typedef uint32_t SensorType; // (5)

typedef uint32_t DriverType; // (6)

typedef uint32_t AlertRule; // (7)

typedef void(*SensorValueCallback)(SensorNumber, SensorValue, void*); // (8)

typedef CheckAlertTimeout(*SensorAlertCallback)(SensorNumber, SensorValue, void*); // (9)

typedef SensorValue(*OnSimulateReadValue)(SensorNumber, int, void*); // (10)

typedef int (*OnSimulateOperable)(SensorNumber, void*); // (11)

enum eSensorType // (12)

{

SENSOR_SPOT = 0,

SENSOR_SMOOTH = 1,

SENSOR_DERIVATIVE = 2,

};

enum eDriverType // (13)

{

DRIVER_SIMULATION = 0,

DRIVER_USB = 1,

DRIVER_ETHERNET = 2

};

enum eAlertRule // (14)

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Виталий Ткаченко читать все книги автора по порядку

Виталий Ткаченко - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Обратные вызовы в C++ отзывы


Отзывы читателей о книге Обратные вызовы в C++, автор: Виталий Ткаченко. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x