2010-07-03 3 views
7

У меня есть следующий класс:V8 FunctionTemplate Class Instance

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

Я хочу метод Зарегистрируйся, чтобы быть доступным из JavaScript. Я добавить его к глобальному объекту, как это:

PluginManager pluginManagerInstance; 

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

Он выдает следующее сообщение об ошибке:

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

Я пытался сделать это, но он не работает. И это неправильно, потому что я хочу, чтобы он вызывал метод Register для pluginManagerInstance.

За исключением того, чтобы сделать метод регистрации статическим или глобальным, любые идеи?

Спасибо.

ответ

5

Вы пытаетесь связать сразу две вещи: экземпляр и метод для вызова на него и иметь его как указатель на функцию. Это, к сожалению, не работает на C++. Вы можете привязать только указатель к простой функции или статический метод . Таким образом, изображение, которое вы добавить статический «RegisterCB» метод и зарегистрировать его в качестве обратного вызова:

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

Теперь, когда вы получаете pluginManagerInstance от? Для этой цели большинство callback-регистрации apis в V8 имеют дополнительный параметр «данных», который будет передан обратно в обратный вызов. Так же FunctionTemplate :: New. Таким образом, вы на самом деле хотите, чтобы связать это следующим образом:

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

Затем данные доступны через args.Data(), и вы можете делегировать фактический метод:

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

Это, несомненно, можно произвести немного легче с некоторыми макросами.

2

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

0

Если вы хотите вызова, что метод, вы должны добавить круглые скобки:

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

Если вы хотите взять его адрес, вы должны добавить &:

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

(Это как раз то, что говорится в сообщении об ошибке.)

+0

Поскольку это вниз проголосовали, кажется, что-то не так с этим. Что с этим не так? – sbi

2

Для примера рассмотрим код в this tutorial. Тот же самый метод, который предлагает mernst, используется для отправки указателя на этот объект, в функцию журнала.

в заголовке:

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; 
    } 

реализация:

//////////////////////////////////////////////////////////////////////// 
// 
// 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

Спасибо, это мне очень помогло. – danijar

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