c++ библиотека с событиями

Озадачился я на неделе в написании библиотеки для своих проектов.

Пока что для виртуального последовательного порта.

Суть такая: код библиотеки выполняется периодически (некий интервал) и опрашивает порт. При получении данных он их парсит и как положено раскидывает.

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

Т.е. нужен некий event, чтобы в основной программе его прикрутить наподобии событий в проектах для форточек кнопочкам при нажатии:

buttonName_click (некие_входные_данные) {
    некий_код;
}

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

myLib_event() {
    код_если_произошло_событие_в_библиотеке;
}

Как подобное можно реализовать?

Вариант копипастить от проекта к проекту не подходит:

  1. Проектов несколько, банально в версиях запутаюсь (куда копирнул, что, а куда ещё нет);
  2. Запарно (постоянно копипастить код и следить за версиями);
  3. Формат пакета девайса может измениться, что потребует изменения кода везде... За тем библиотеки и пишут, чтобы по 100500 раз не развозить всяких копий. С библиотекой достаточно просто рекомпильнуть новую версию софтины;
  4. Может изменится логика, когда надо выводить, а когда нет;
  5. Проще новый проект накидать, или изменить существующий. Ядро трогать нет нужды, только вывод.

Дополнительно: Как расшаривать пространство под данные девайса. Т.е. создавать общее некое пространство (массив), чтобы библиотека туды кидала готовые данные и пинала прогу, что есть событие... А та могла достать эти данные и уже по-своему их вывести-перенести-обработать-сохранить и всякое...


Ответы (1 шт):

Автор решения: Александр

Попробую кратко описать возможные варианты:

1.Это Си подход, когда в библиотеку передаем указатель на функцию обработчик

#include <iostream>

typedef void (*FunctionPtr)(int);

class MyLibClass
{
public:
    void addListener(FunctionPtr _func)
    {
        m_func = _func;
    }

    void someLibEventLoop()
    {
        //..

        for(int i = 0 ; i < 5 ; i++)
        {
            if(m_func)
            {
                m_func(i);
            }
        }
    }

    FunctionPtr m_func = nullptr;
};

void clientFunction(int _v)
{
    std::cout << __FUNCTION__ << " | " << _v << std::endl;
}

int main(int argc, char *argv[])
{
    MyLibClass libClass;

    libClass.addListener(clientFunction);
    libClass.someLibEventLoop();

    return 0;
}

2.Более продвинутый вариант - использовать std::function, тогда для подписки можно использовать лямбды

#include <iostream>
#include <functional>

class MyLibClass
{
public:
    void addListener(std::function<void(int)> _func)
    {
        m_func = _func;
    }

    void someLibEventLoop()
    {
        //..

        for(int i = 0 ; i < 5 ; i++)
        {
            if(m_func)
            {
                m_func(i);
            }
        }
    }

    std::function<void(int)> m_func = nullptr;
};

int main(int argc, char *argv[])
{
    MyLibClass libClass;

    libClass.addListener([](int _v)
    {
        std::cout << __FUNCTION__ << " | " << _v << std::endl;
    });
    libClass.someLibEventLoop();

    return 0;
}

3.4. Использовать готовые системы, типа сигналы слоты из Qt или Boost Signals

→ Ссылка