我有以下课程:
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方法静态或全局,还有任何想法吗?
感谢。
答案 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) );
^
(这正是错误信息所说的。)