2010-07-03 12 views
7

Mam następujące klasy:V8 FunctionTemplate Klasa Instancja

class PluginManager 
{ 
public: 
    Handle<Value> Register(const Arguments& args); 
    Handle<ObjectTemplate> GetObjectTemplate(); 
}; 

chcę metoda Rejestracja być dostępne z JavaScript. I dodać go do globalnego obiektu tak:

PluginManager pluginManagerInstance; 

global->Set(String::New("register"), FunctionTemplate::New(pluginManagerInstance.Register)); 

To rzuca się następujący błąd:

'PluginManager::Register': function call missing argument list; use '&PluginManager::Register' to create a pointer to member

Próbowałem to zrobić, ale to nie działa albo. I nie jest to poprawne, ponieważ chcę wywołać metodę Register z pluginManagerInstance.

Z wyjątkiem tworzenia metody Register static lub global, żadnych pomysłów?

Dzięki.

Odpowiedz

5

Próbujesz powiązać dwie rzeczy jednocześnie: instancję i metodę wywołania na niej, i sprawić, że będzie wyglądać jak wskaźnik funkcji. To niestety nie działa w C++. Możesz powiązać wskaźnik tylko z funkcją prostą lub ze statyczną metodą . Tak więc obraz dodać statyczny „RegisterCB” metody i zarejestrować go jako callback:

static Handle<Value> RegisterCB(const Arguments& args); 
...FunctionTemplate::New(&PluginManager::RegisterCB)... 

Teraz skąd uzyskać pluginManagerInstance od? W tym celu większość apisów rejestracji wywołań zwrotnych w V8 ma dodatkowy parametr "danych", który zostanie przekazany z powrotem do wywołania zwrotnego. Tak działa funkcja FunctionTemplate :: New. Więc faktycznie chcą związać go tak:

...FunctionTemplate::New(&PluginManager::RegisterCB, 
         External::Wrap(pluginManagerInstance))... 

Następnie dane są dostępne za pośrednictwem args.Data() i można delegować do rzeczywistego sposobu:

return ((PluginManager*)External::Unwrap(args.Data())->Register(args); 

Można to z pewnością popełnił trochę łatwiej z niektórymi makrami.

2

Najprawdopodobniej będziesz musiał zrobić to statycznie. Nie zapomnij funkcji składowych, które ukrywają ten parametr jako pierwszy argument. Z tego powodu rzadko działają dobrze jako prototypy wskaźników funkcyjnych.

0

Jeśli chcesz rozmowy tej metody, trzeba dodać nawiasy:

lobal->Set(String::New("register") 
      , FunctionTemplate::New(pluginManagerInstance.Register())); 
                   ^^ 

Jeśli chcesz wziąć swój adres, trzeba dodać &:

lobal->Set(String::New("register") 
      , FunctionTemplate::New(&PluginManager::Register)); 
           ^

(Dokładnie o tym informuje komunikat o błędzie.)

+0

ponieważ był dół głosowali, wydaje się, że coś jest nie tak z tym. Co jest z tym nie tak? – sbi

2

Na przykład spójrz na kod w this tutorial. Ta sama metoda, o której mowa powyżej, jest używana do wysyłania wskaźnika do tego obiektu, do funkcji dziennika.

w nagłówku:

virtual void log(const string &str); 
    static Handle<Value> logCallback(const Arguments &args); 

    Local<FunctionTemplate> makeStaticCallableFunc(InvocationCallback func); 
    Local<External> classPtrToExternal(); 

    //////////////////////////////////////////////////////////////////////// 
    // 
    // Converts an External to a V8TutorialBase pointer. This assumes that the 
    // data inside the v8::External is a "this" pointer that was wrapped by 
    // makeStaticCallableFunc 
    // 
    // \parameter data Shoudld be v8::Arguments::Data() 
    // 
    // \return "this" pointer inside v8::Arguments::Data() on success, NULL otherwise 
    // 
    ////////////////////////////////////////////////////////////////////////   
    template <typename T> 
    static T *externalToClassPtr(Local<Value> data) 
    { 
     if(data.IsEmpty()) 
      cout<<"Data empty"<<endl; 
     else if(!data->IsExternal()) 
      cout<<"Data not external"<<endl; 
     else 
      return static_cast<T *>(External::Unwrap(data)); 

     //If function gets here, one of the checks above failed 
     return NULL; 
    } 

realizacja:

//////////////////////////////////////////////////////////////////////// 
// 
// Wrap a callback function into a FunctionTemplate, providing the "this" 
// pointer to the callback when v8 calls the callback func 
// 
// \parameter func Static callback to be used in FunctionTemplate 
// 
// \return Local<FunctionTemplate> containing func 
// 
//////////////////////////////////////////////////////////////////////// 
Local<FunctionTemplate> V8TutorialBase::makeStaticCallableFunc(InvocationCallback func) 
{ 
    HandleScope scope; 
    Local<FunctionTemplate> funcTemplate = FunctionTemplate::New(func, classPtrToExternal()); 
    return scope.Close(funcTemplate); 
} 

//////////////////////////////////////////////////////////////////////// 
// 
// Makes the "this" pointer be an external so that it can be accessed by 
// the static callback functions 
// 
// \return Local<External> containing the "this" pointer 
//////////////////////////////////////////////////////////////////////// 
Local<External> V8TutorialBase::classPtrToExternal() 
{ 
    HandleScope scope; 
    return scope.Close(External::New(reinterpret_cast<void *>(this))); 
} 

Handle<Value> V8TutorialBase::logCallback(const Arguments &args) 
{ 
    HandleScope scope; 

    ..... 

    V8TutorialBase *objPtr = externalToClassPtr<V8TutorialBase>(args.Data()); 
    String::Utf8Value val(Local<String>::Cast(args[0])); 
    objPtr->log(*val); // log is a non static member function 
    // or you can directly do anything that you would do in a member function using the objPtr 

    return v8::Null(); 
} 
+0

Dzięki, to mi bardzo pomogło. – danijar