2014-01-22 4 views
0

У меня возникла проблема с этим типом реализации обратного вызова в C++. В приведенном ниже коде я хотел бы сохранить обратный вызов в «OnRenderingComplete». Однако у меня возникли проблемы с запоминанием параметров «ad» и «callback» для «adOnRenderingComplete». Как это реализовано на C++?Подражание специальному обратному вызову JavaScript в C++

var adOnRenderingComplete = function(ad, callback) { 

}; 

var setAdPlaybackCallbacks = function(ad, callback) { 

    OnRenderingComplete = function() { adOnRenderingComplete.call(this, ad, callback); }; 
}; 

В JavaScript, кажется, что это возможно, так как там может быть встроена функция хранения параметров «объявления» и «обратного вызова» ... но я не знаю, как это будет сделано в C++. В конечном итоге мне бы хотелось вызвать OnRenderingComplete(), при этом он «запоминал» параметры «объявление» и «обратный вызов».

Мне тяжело. Я не могу понять этого. Единственное, что я могу придумать, это определить класс внутри функции и передать функцию этого класса в OnRenderingComplete. Но даже в этом случае нижеследующее неверно и не компилируется.

void testCall(void (*callback)()) 
{ 
    callback(); 
} 

void test1() 
{ 
    class blah 
    { 
    public: 
     int a; 
     int b; 
     void c() 
     { 
      cout << "a * b = " << a*b << endl; 
     }; 
    }; 

    blah ex; 
    ex.a = 5; 
    ex.b = 3; 

    void(*OnRenderingComplete)() = ex.c; 
    testCall(OnRenderingComplete); // I would like to have this print the value of a*b 
} 

По существу, я пытаюсь захватить "ex.c" в переменной обратного вызова "OnRenderingComplete". Но в то же время я хотел бы получить значение ex.a и ex.b, так что ex.c можно вызвать, «запоминая» данные для «a» и «b». После выполнения вызова «testCall (OnRenderingComplete)» я хотел бы, чтобы функция наверху для testCall() могла печатать значение a * b.

+0

Вы можете использовать lambdas, если вы компилируете на C++ 11. – Synxis

+0

Спасибо за ваш комментарий Synxis. Можно ли обойтись без C++ 11? – codeshark

+0

Да, но это будет сложнее, в зависимости от того, можете ли вы использовать boost или нет. – Synxis

ответ

2

несколько решений (нажмите на названия для живого примера):

C++11:

#include <functional> 

struct MyClass 
{ 
    typedef std::function<void (int, bool)> CallbackType; 
    typedef std::function<void (int, float, bool)> AnotherCallbackType; 
    CallbackType callback; 

    void setCallback(AnotherCallbackType c, float param) 
    { 
     callback = [&](int a, bool b) { c(a, param, b); }; 
     // Calling the callback: 
     callback(42, false); 
     // With lambdas, it is almost like in Javascript, 
     // you can embed all parameters you want. ex: 
     std::function<void()> func = [&](){ c(2, param, true); }; 
     func(); // will call c(2, param, true); 
    } 
}; 

C++03, with Boost:

#include <boost/function.hpp> 
#include <boost/bind.hpp> 

struct MyClass 
{ 
    typedef boost::function<void (int, bool)> CallbackType; 
    typedef boost::function<void (int, float, bool)> AnotherCallbackType; 
    CallbackType callback; 

    void setCallback(AnotherCallbackType c, float param) 
    { 
     callback = boost::bind(c, _1, param, _2); 
     // Calling the callback: 
     callback(42, false); 
     // This will call: c(42, param, false) 
     // The 'param' float parameter has been retained. 
     // It is possible to retain all parameters when binding, ex: 
     boost::function<void()> func = boost::bind(c, 2, param, true); 
     func(); // will call c(2, param, true); 
    } 
}; 

C++03, without Boost:

struct MyClass 
{ 
    typedef void (MyClass::* CallbackType)(int, float); 
    CallbackType callback; 

    void onRenderCallback(int param1, float param2) {} 
    void setCallback(CallbackType c) 
    { 
     callback = c; 
     // Calling the callback: 
     (this->*callback)(42, 3.14f); 
     // Note that it is possible to embed the parameters 
     // but that will need to create a class, basically it means you will reimplement Boost.Bind... 
    } 
}; 

Теперь вернусь к коду:

void(*OnRenderingComplete)() = ex.c; 

Для указателя на функцию, я серьезно советую использовать определения типов:

typedef void (*OnRenderingCompleteType)(); 
OnRenderingCompleteType callback = ...; 

Затем ex.c имеет следующий вид : void (blah::*)(). Обратите внимание на blah::*, потому что это функция-указатель-член, не указатель на функцию (функции-члены - это специальные функции). Именно поэтому назначение не компилируется.

+0

Так, например, пример того, что я хотел бы достичь, следующий: OnRenderingCometeType callback = (this -> * callback) (42, 3.14f); Я хотел бы иметь возможность называть «callback()» и помнить параметры 42 и 3.14f. – codeshark

+0

У вас есть доступ к C++ 11? Опубликуйте свой компилятор в качестве комментария (или в вопросе). Синтаксис '(this -> * func) (args)' предназначен для функции указатель-член, это самый низкий уровень в отношении обратных вызовов. Я положил это в ответ на его полноту, но советую вам использовать C++ 11 (или, по крайней мере, Boost). – Synxis

+0

Спасибо! Я буду использовать C++ 11 для этого и использовать метод std :: bind! Отлично. Спасибо за вашу помощь. – codeshark

Смежные вопросы