Виталий Ткаченко - Обратные вызовы в C++
- Название:Обратные вызовы в C++
- Автор:
- Жанр:
- Издательство:Array SelfPub.ru
- Год:2021
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Виталий Ткаченко - Обратные вызовы в C++ краткое содержание
Обратные вызовы в C++ - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
{
NoError = 0,
NotInitialized = 1,
UnknownSensorType = 2,
UnknownSensorNumber = 3,
SensorIsNotOperable = 4,
DriverIsNotSet = 5,
InvalidArgument = 6,
NotSupportedOperation = 7,
InitDriverError = 8
};
class sensor_exception : public std::exception // (2)
{
public:
sensor_exception(SensorError error);
SensorError code() const;
virtual const char* what() const;
static void throw_exception(SensorError error); // (3)
private:
SensorError code_;
};
}; //namespace sensor
В строке 1 объявлены коды возможных ошибок, в строке 2 объявлен класс исключений. Если при выполнении где-то в коде возникает ошибка, то в этом месте нужно вызвать метод, объявленный в строке 3. Указанный метод выбросит исключение с соответствующим кодом.
6.2.3. Драйвер
Драйвер предназначен для взаимодействия с аппаратным обеспечением. Класс, представляющий обобщенный интерфейс для работы с драйвером, приведен в Листинг 88.
namespace sensor
{
class IDriver
{
public:
virtual void initialize() = 0; // (1)
virtual void activate(SensorNumber number) = 0; // (2)
virtual bool isOperable(SensorNumber number) = 0; // (3)
virtual SensorValue readSpot(SensorNumber number) = 0; // (4)
virtual SensorValue readSmooth(SensorNumber number) = 0; // (5)
virtual SensorValue readDerivative(SensorNumber number) = 0; // (6)
virtual ~IDriver() = default;
static DriverPointer createDriver(DriverType type); // (7)
};
}; //namespace sensor
В строке 1 объявлен метод для инициализации драйвера. В строке 2 объявлен метод для активации датчика. В строке 3 объявлен метод, возвращающий признак работоспособности датчика. В строках 4, 5 и 6 объявлены методы для чтения соответственно текущих, сглаженных и производных значений. Метод в строке 7 представляет собой фабрику классов, в котором происходит создание класса соответствующего типа.
От общего интерфейса наследуются классы, реализующие драйверы различных типов. В нашей системе реализованы три типа драйверов: драйвер для работы с шиной USB; драйвер для работы через сеть Ethernet; имитируемый драйвер. Диаграмма классов изображена на Рис. 28.

Рис. 28. Диаграмма классов, реализующих драйверы
Драйверы для работы с физическими устройствами формируют команды, посылают их через соответствующие протоколы и возвращают результаты. Реализацию этих драйверов мы рассматривать не будем, поскольку работа с hardware – это отдельная тема, для изучения которой требуется не одна книга. Для нас представляет интерес реализация имитируемого драйвера.
Очевидно, что имитируемый драйвер должен возвращать заранее заданные значения. Самое простое решение, лежащее на поверхности, заключается в том, чтобы хранить эти значения в глобальных или статических переменных и возвращать их в соответствующих методах. Однако в этом случае имитация будет очень примитивной: для всех датчиков будет возвращаться одно и то же значение. Можно хранить свое возвращаемое значение в каждом классе датчика, что больше похоже на работу в реальной системе, но это также не лишено недостатков: мы не можем моделировать изменения показателей в динамике. Лучшим решением было бы предоставить возможность пользователю возвратить значение в момент запроса, для чего нам, конечно же, понадобится обратный вызов. Обратный вызов будет использоваться по схеме «Запрос данных» (см. п. 1.2.1).
Итак, для реализации интерфейса имитируемого драйвера нам понадобятся дополнительные методы и определения (см. Листинг 89).
class DriverSimulation : public IDriver
{
public:
enum ReadType { READ_SPOT = 0, READ_SMOOTH = 1, READ_DERIVATIVE = 2 }; // (1)
using OnReadValue = std::function; // (2)
using OnOperable = std::function; // (3)
void initialize() override;
void activate(SensorNumber number) override;
bool isOperable(SensorNumber number) override;
void setDefaultValue(SensorValue value); // (4)
void setDefaultOperable(bool isOperable); // (5)
void setReadValue(OnReadValue value); // (6)
void setOperable(OnOperable operable); // (7)
SensorValue readSpot(SensorNumber number) override; // (8)
SensorValue readSmooth(SensorNumber number) override; // (9)
SensorValue readDerivative(SensorNumber number) override; // (10)
static IDriver* create();
protected:
DriverSimulation();
private:
OnReadValue getValue_; // (11)
OnOperable getOperable_; // (12)
SensorValue defaultValue_ = 0; // (13)
bool defaultOperable_ = true; // (14)
};
В строке 1 объявляется перечисление для указания используемого метода чтения показателей. В строке 2 и 3 объявляются типы для обратных вызовов. Переменные соответствующих типов для хранения вызовов объявлены в строках 11 и 12. Настройка вызовов производится в методах 6 и 7. Кроме того, объявляются переменные для хранения значений по умолчанию (строки 13 и 14), эти переменные настраиваются в методах 4 и 5.
Реализацию чтения показателей продемонстрируем на примере получения текущего значения датчика (Листинг 90).
SensorValue DriverSimulation::readSpot(SensorNumber number)
{
if (getValue_) // (1)
{
return getValue_(number, READ_SPOT); // (2)
}
else
{
return defaultValue_; // (3)
}
}
В строке 1 проверяется, настроен ли обратный вызов. Если настроен, то через него запрашивается значение для соответствующего датчика. Информацией вызова здесь является номер датчика и метод чтения показателей (строка 2). Если обратный вызов не настроен, то возвращается значение по умолчанию (строка 3).
6.2.4. Датчик
Обобщенный интерфейсный класс для работы с датчиком приведен в Листинг 91.
namespace sensor
{
class ISensor
{
public:
virtual void setDriver(DriverPointer driverPointer) = 0; // (1)
virtual DriverPointer getDriver() = 0; // (2)
virtual double getValue() = 0; // (3)
virtual bool isOperable() = 0; // (4)
virtual ~ISensor() = default;
static SensorPointer createSensor(SensorType type, SensorNumber number, DriverPointer driverPointer); // (5)
};
}; //namespace sensor
В строке 1 объявлен метод для настройки драйвера, с которым будет работать датчик. Получить используемый драйвер можно с помощью метода 2. В строках 3 и 4 объявлены методы для получения текущего значения датчика и определения его работоспособности. В строке 5 объявлен метод для создания экземпляра класса соответствующего типа.
В соответствии с требованиями нам необходимо реализовать датчики, которые бы возвращали текущие, сглаженные и производные значения показателей. Для каждого способа реализован отдельный класс; диаграмма классов изображена на Рис. 29.
Читать дальшеИнтервал:
Закладка: