Объектная функция C ++ для указателя на функцию - PullRequest
2 голосов
/ 14 августа 2011

Я использую библиотеку C внутри своего приложения C ++.В библиотеке есть функция со следующей подписью:

void awe_webview_set_callback_js_callback(awe_webview* webview, void (*callback)(awe_webview* caller, const awe_string* object_name, const awe_string* callback_name, const awe_jsarray* arguments));

Я пытаюсь установить функцию в качестве обратного вызова, и я хотел бы иметь возможность использовать следующую функцию-член класса

void BattleScreen::HandleWebViewCallbacks(awe_webview* WebView, const awe_string* object, const awe_string* callback, const awe_jsarray* arguments)
{
    //handling code
}

Я не могу связать это напрямую и на основании этого http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2 У меня есть возможное решение, где я бы создал статический член для обработки обратного вызова (так как на этом сайте все должно быть хорошо) и добавьте статический экземпляр этого класса для вызова статического члена.

то есть добавьте в BattleScreen следующее:

static BattleScreen* callbacktarget;
static BattleScreen::TopLevelHandleWebViewCallbacks(awe_webview* WebView, const awe_string* object, const awe_string* callback, const awe_jsarray* arguments)
{
      callbacktarget->HandleWebviewCallbacks(WebView, object, callback, arguments);
}

свяжите его в конструкторе следующим образом:

awe_webview_set_callback_js_callback(this->GetWebView(), static_cast<void (*)(awe_webview*, const awe_string*, const awe_string*, const awe_jsarray*)>(&BattleScreen::TopLevelHandleWebViewCallbacks));

и назначить объект в callbacktarget в конструкторе.

BattleScreen::callbacktarget = this;

Проблема в том, что у меня нет способа узнать, сколько из этих классов я буду иметь одновременно (это будетбыть минимальным, но, возможно, больше 1).Я подумал о том, чтобы сделать callbacktarget вектором BattleScreen *, который я могу перебирать внутри TopLevelHandleWebViewCallbacks и сравнивать примерно так:

if (callbacktargets[index]->GetWebview() == WebView)
{
     callbacktargets[index]->HandleWebviewCallbacks(WebView, object, callback, arguments);
}

, но проблема здесь в том, что я сравниваю только указатели awe_webview, которые кажутся действительноплохая идея.Библиотека имеет закрытый исходный код, а awe_webview являются конструкциями C, поэтому я не вижу, из чего они состоят, и есть ли какие-либо свойства, которые могли бы сделать более подходящее сравнение.Есть ли хорошее решение для этого?

Если мне неясно или вам нужна дополнительная информация, дайте мне знать.

Заранее спасибо

Ответы [ 2 ]

2 голосов
/ 14 августа 2011

Тот факт, что обратные вызовы получают указатель awe_webview, более или менее доказывает, что их сравнение - это то, что они ожидают от вас.

Однако я бы изменил ваше решение, чтобы использовать глобальную карту между веб-просмотрами в BattleScreens:

static std::map<awe_webview*, BattleScreen*> gWebViewBattleScreen;

Затем имейте один глобальный обратный вызов, который выбирает объект BattleScreen и вызывает его метод:

static void webviewCallback(awe_webview* caller, ......)
{
    if (gWebViewBattleScreen.find(caller) != gWebViewBattleScreen.end())
        gWebViewBattleScreen[caller]->HandleWebViewCallbacks(......)
}

Хорошие библиотеки позволяют передавать указатель контекста с помощью обратного вызова, поэтому вы можете назначить что-то вроде BattleObject * для каждого установленного обратного вызова:

void set_nice_callback(void (*callback)(Params params, void* context), void* context);

Библиотека, которую вы используете, выглядит не очень красиво :) Вы можете указать на это своим разработчикам.

2 голосов
/ 14 августа 2011

Три решения:

  1. Убедитесь, что библиотека не позволяет привязывать произвольный указатель «контекста» к каждому awe_webview. Они обычно делают. Если это так, сохраните указатель на BattleScreen, а когда вызывается статический обратный вызов, извлеките указатель this из «контекста» webview и вызовите функцию-член для этого указателя.

  2. Используйте глобальный map<awe_webview*, BattleScreen*>. В статическом обратном вызове найдите BattleScreen, соответствующий webview. Требуется блокировка глобальной карты, а не красивая.

    Примечание: использование указателя на веб-просмотр в качестве уникального идентификатора почти наверняка нормально. Это всегда уникально.

  3. Используйте громоотводы (например, http://www.codeproject.com/KB/cpp/thunk32.aspx).

...