2013-03-20 9 views
5

mi piacerebbe fare qualcosa di simile al seguente in node.js ...Chiamata di una funzione che utilizza un oggetto avvolto come un argomento in Node.js e v8

var a = new A(); var b = new B();

// onTick dovrebbe essere una funzione che accetta un'istanza di B come argomento

a.onTick = funzione (Binst) { .... }

a.loop();

significa che A ha una proprietà "onTick" che è una funzione che viene chiamata all'interno del ciclo. Nota che A e B sono definiti come C++ funzioni avvolti, ecco le definizioni

void AClass::Init(Handle<Object> target) { 
    Local<FunctionTemplate> tpl = FunctionTemplate::New(New); 
    tpl->SetClassName(String::NewSymbol("A")); 
    tpl->InstanceTemplate()->SetInternalFieldCount(1); 
    tpl->PrototypeTemplate()->Set(String::NewSymbol("tick"), 
     FunctionTemplate::New(Tick)->GetFunction()); 
    tpl->PrototypeTemplate()->Set(String::NewSymbol("loop"), 
    FunctionTemplate::New(Loop)->GetFunction()); 

    constructor = Persistent<Function>::New(tpl->GetFunction()); 
    constructor->InstanceTemplate()->SetAccessor(String::New("onTick"), GetOnTick, SetOnTick); 
    target->Set(String::NewSymbol("A"), constructor); 
} 

Handle<Value> AClass::New(const v8::Arguments &args) { 
    HandleScope scope; 
    AClass* acls = new AClass(); 
    WrappedAClass* wrappedA = new WrappedAClass(); 
    acls->wrappedAInst_ = wrappedA; 
    window->Wrap(args.This()); 
    return args.This(); 
} 
Handle<Value> AClass::Loop(const Arguments &args) { 
    HandleScope scope; 
    AClass* acls = ObjectWrap::Unwrap<AClass>(args.This()); 
    acls->wrappedInst_->loop(); 
    return scope.Close(Undefined()); 
} 

Credo che questo sia il modo di impostare il getter e setter di una proprietà

Handle<Function> GetOnTick(Local<String> property, const AccessorInfo& info) { 
    AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder()); 
    return acls->onTick_; 
} 

void SetOnTick(Local<String> property, Local<Function> value, const AccessorInfo& info) { 
    AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder()); 

    acls->onTick_ = Persistent<Function>::New(value); 
    //Here's where I know I'm doing it wrong 
    void func(WrappedClassB* wcb) { 
    const unsigned argc = 1; 
    Local<Value> argv[argc] = 
     { Local<Value>::New(BClass::Instantiate(wcb)) }; 
    acls->onTick_->Call(Context::GetCurrent()->Global(), argc, argv); 
    } 
    acls->wrappedAInst_->setTickFunc(func); 
} 

Quello che sto cercando di do è prendere la funzione dall'impostazione onTick (che prende un'istanza di Class B) e avvolgerla in una funzione che instace un nuovo BClass.

Comunque heres la definizione per BClass

Persistent<Function> BClass::constructor; 
BClass::BClass() { 
} 
BClass::~BClass() { 
} 

void BClass::Init(Handle<Object> target) { 
    Local<FunctionTemplate> tpl = FunctionTemplate::New(New); 
    tpl->SetClassName(String::NewSymbol("B")); 
    tpl->InstanceTemplate()->SetInternalFieldCount(1); 
    constructor = Persistent<Function>::New(tpl->GetFunction()); 
    target->Set(String::NewSymbol("B"), constructor); 
} 

Handle<Value> BClass::New(const v8::Arguments &args) { 
    HandleScope scope; 
    BClass* bcls = new BClass(); 
    bcls->Wrap(args.This()); 
    WrappedBClass* wrappedB = new WrappedBClass(); 
    bcls->wrappedBInst_ = wrappedB; 
    return args.This(); 
} 
Handle<Value> BClass::Instantiate(const WrappedBClass &wbc) { 
    HandleScope scope; 
//I know the following is wrong but it shows what I am trying to do 
    BClass* bcls = new BClass(); 
    bcls->wrappedBInst_ = wbc; 
    return scope.Close(Local<v8::Value>::New(bcls)); 
} 

Sia AClass e BClass utilizzare un'altra classe C++ e salvare l'istanza come una proprietà (wrappedBInst, wrappedAInst) credo che mi serve la funzione Instantiate per quando ho bisogno di convertire un'istanza di WrappedBClass in una BClass.

WrappedBClass non fa nulla di speciale ma WrappedAClass eredita una classe che ha un loop e una funzione onTick, e la funzione onTick è dove devo chiamare la mia funzione Javascript, quindi in WrappedAClass ho eseguito overTick e aggiunto una funzione setTickFunc .

class WrappedAClass : public InheritedClass{ 
public: 
    void setTickFunc(void (*func)(WrappedBClass*)){ 
    tickFunc = func; 
    } 
protected: 
    void tickFunc; 
    virtual void onTick(WrappedBClass* wbc){ 
    if(tickFunc){ 
     tickFunc(wbc); 
    } 
    } 
} 

Quindi l'unico modo penso che posso entrare nel loop e utilizzare una funzione JavaScript come la funzione onTick è quello di avvolgere prima la funzione javascript in un C++ funzione e quindi impostare tale funzione chiamando setTickFunc() . Sto andando su questo nel modo giusto?

Sono un programmatore decente, ma solo di recente ha iniziato a lavorare con C++ in modo scusare i miei errori evidenti, il più grande è più probabile che questo:

void SetOnTick(Local<String> property, Local<Function> value, const AccessorInfo& info) { 
     AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder()); 

     acls->onTick_ = Persistent<Function>::New(value); 
     //Here's where I know I'm doing it wrong 
     void func(WrappedClassB* wcb) { 
     const unsigned argc = 1; 
     Local<Value> argv[argc] = 
      { Local<Value>::New(BClass::Instantiate(wcb)) }; 
     acls->onTick_->Call(Context::GetCurrent()->Global(), argc, argv); 
     } 
     acls->wrappedAInst_->setTickFunc(func); 
    } 

Sto ancora cercando di capire come creare un funzione anonima che trattiene il valore di una variabile dall'esterno (acls). Non penso che le chiusure siano valide qui, la chiave è che questa funzione ha solo un argomento (WrappedClassB * wcb) perché deve essere impostato come funzione OnTick.

risposta

0

Non è necessario creare una funzione anonima in C++. Forse puoi definire il tuo WrappedAClass in questo modo.

class WrappedAClass : public InheritedClass{ 
public: 
    void setTickFunc(Local<Function> jsFn){ 
    HandleScope scope; 
    jsTickFunc = Persistent<Function>::New(jsTickFunc); 
    } 
protected: 
    Persistent<Function> jsTickFunc; 
    virtual void onTick(WrappedBClass* wbc){ 
    HandleScope scope; 
    if(jsTickFunc.IsEmpty()) 
     return; 
    const unsigned argc = 1; 
    Local<Value> argv[argc] = 
    { Local<Value>::New(BClass::Instantiate(wcb)) }; 
    jsTickFunc->Call(Context::GetCurrent()->Global(), argc, argv); 
    } 
} 

Prestare attenzione alla funzione SetOnTick, il secondo parametro è di tipo Local<Value> non Local<Function>. C++, non come js, è un linguaggio tipizzato statico.Forse puoi definire il tuo Setter SetOnTick leccando questo:

void SetOnTick(Local<String> property, Local<Value> value, const AccessorInfo& info){ 
    AClass* acls = ObjectWrap::Unwrap<AClass>(info.Holder()); 
    if (value->IsFunction()) 
    acls->wrappedAInst_->setTickFunc(Local<Function>::Cast(value)); 
}