Создание метода-оболочки в C ++ во время выполнения - известный прототип - PullRequest
0 голосов
/ 17 сентября 2018

В настоящее время я оборачиваюсь вокруг API, который берет указатели на функции и вызывает их в какой-то момент. Единственная проблема заключается в том, что прототип этой функции обратного вызова предоставляет указатель на состояние, которое я обертываю, вместо моего нового класса. Моя цель - скрыть исходный API от пользователя, поэтому мне нужен способ динамического создания метода, который вызывает другую функцию, прототип которой вместо этого является моим новым классом. Вот упрощенная визуализация кода.

struct Old_API
{
    public:
        typedef int (*OldCallback)(Old_API*);
        void RegisterCallback(OldCallback);
};

class New_API
{
    private:
        Old_API* m_WrappedState;

    public:
        typedef int (*NewCallback)(New_API*);

        New_API() { m_WrappedState = new Old_API; }

        void RegisterCallback(NewCallback func)
        {
            // Pseudocode, obviously won't work
            // This is the actual method that would be called back from Old_API
            // It acts as a buffer to call the "new" format of callbacks
            int CallbackLayer(Old_API* state)
            {
                m_WrappedState = state;
                return func(this);
            }

            m_WrappedState->RegisterCallback(&CallbackLayer);
        }
};

// This is what it would look like in runtime

int SomeCallback(New_API*)
{
    // Code
}

New_API* state;

int main()
{
    state = new New_API;
    state->RegisterCallback(&SomeCallback);

    return 0;
}

Технические характеристики

  • Должно быть сделано во время выполнения, поэтому передача указателя функции в качестве параметра шаблона не будет работать.

  • Экземпляры New_API создаются пользователем и практически не сохраняют состояния - они просто заключаются в произвольные Old_API экземпляры.

  • Old_API экземпляры передаются в функцию обратного вызова и не отображаются в один New_API экземпляр. Метод «CallbackLayer» предназначен для того, чтобы избавить пользователя от необходимости самостоятельно настраивать состояние, тем самым скрывая реализацию Old_API.

1 Ответ

0 голосов
/ 17 сентября 2018

Если вы полностью упаковываете интерфейс, это упрощается.

Сначала New_API регистрирует своего собственного слушателя на Old_API, используя любые средства, которые Old_API предлагает связать обратный вызов с этим экземпляром.из New_API (может быть просто полем в Old_API или, если оно недоступно, даже что-то вроде статического unordered_map<Old_API*, New_API*>).

Тогда New_API имеет свою собственную систему регистрации слушателей.(Вы показываете здесь указатели функций, но это думает C ... в худшем случае у вас должно быть что-то, что занимает std::function.)

Когда New_API получает свое уведомление, оно просто уведомляет свое собственноеслушатель (и) по очереди.Между слушателями нет прямого отображения: Old_API будет иметь ровно одного слушателя, независимо от того, сколько слушателей на New_API.

...