V8 FunctionTemplate类实例

时间:2010-07-03 12:00:12

标签: c++ static instance v8

我有以下课程:

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

我希望可以从JavaScript访问Register方法。我将它添加到全局对象中:

PluginManager pluginManagerInstance;

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

它会抛出以下错误:

  

'PluginManager :: Register':函数   调用缺少参数列表;使用   '&amp; PluginManager :: Register'创建一个   指向成员的指针

我试图这样做,但它也不起作用。并且它不正确,因为我希望它调用 pluginManagerInstance 的Register方法。

除了使Register方法静态或全局,还有任何想法吗?

感谢。

4 个答案:

答案 0 :(得分:7)

你试图同时绑定两个东西:实例和调用它的方法,让它看起来像一个函数指针。不幸的是,这在C ++中不起作用。您只能将指针绑定到普通函数或静态方法。因此,您可以添加静态“RegisterCB”方法并将其注册为回调:

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

现在从哪里获取pluginManagerInstance?为此,V8中的大多数回调注册apis都有一个额外的“data”参数,该参数将被传递回回调。 FunctionTemplate :: New也是如此。所以你实际上想要像这样绑定它:

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

然后可以通过args.Data()获取数据,您可以委托实际方法:

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

使用某些宏可以肯定会更容易。

答案 1 :(得分:2)

您可能需要将其设为静态。不要忘记成员函数将隐藏此参数作为第一个参数。因此,它们很少作为函数指针原型工作。

答案 2 :(得分: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();
}

答案 3 :(得分:0)

如果您想 调用 该方法,则必须添加括号:

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

如果您想 获取其地址 ,则必须添加&

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

(这正是错误信息所说的。)