Hello,

I am using V8 to expose a C++ API to JavaScript, and I have a use-case where 
one would need to have a JavaScript class that inherit from a C++ class. I've 
seen from V8 test code how they test the inheritance  thing there, but I 
couldn't find anything that was specific to my case. I've exhausted all 
resources that I could find on Google on this issue so I figured someone might 
help here.

I've attached a simplified code snippet for my case. It contains the class that 
I expose and the way I use it in JavaScript, so maybe someone can spot what I 
am missing.

Thanks in advance.

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
#include "v8.h"

class CppClass {
public:
    CppClass() {
        v8::Isolate* isolate = v8::Isolate::GetCurrent();

        mAnotherCppClass = new AnotherCppClass();
        mJsAnotherCppClass.Reset(isolate, 
AnotherCppClass::Wrap(mAnotherCppClass));
    }

    float MyCppMethod() {
        return 2.f + 2.f;
    }

    // V8 Stuff
    static v8::Local<v8::FunctionTemplate> Bind() {
        v8::Isolate* isolate = v8::Isolate::GetCurrent();

        auto funcTemplate = v8::FunctionTemplate::New(isolate, 
CppClass_Constructor);
        funcTemplate->SetClassName(v8::String::NewFromUtf8(isolate, 
"CppClass"));
        funcTemplate->InstanceTemplate()->SetInternalFieldCount(1);

        
funcTemplate->InstanceTemplate()->SetAccessor(v8::String::NewFromUtf8(isolate, 
"object"), GetObject);
        funcTemplate->PrototypeTemplate()->Set(v8::String::NewFromUtf8(isolate, 
"myCppMethod", v8::NewStringType::kNormal).ToLocalChecked(),
            v8::FunctionTemplate::New(isolate, MyCppMethod_Callback));

        functionTemplate.Reset(isolate, funcTemplate);
        return functionTemplate.Get(isolate);
    }

    static v8::Local<v8::Object> Wrap(CppClass* obj) {
        v8::Isolate* isolate = v8::Isolate::GetCurrent();
        v8::EscapableHandleScope handleScope(isolate);

        v8::Local<v8::Object> instance = 
functionTemplate->InstanceTemplate()->NewInstance();
        instance->SetInternalField(0, obj);

        return handleScope.Escape(instance);
    }

    static CppClass* Unwrap(v8::Local<v8::Object> object) {
        return (CppClass*)object->GetInternalField(0);
    }

    static void CppClass_Constructor(const v8::FunctionCallbackInfo<v8::Value>& 
args) {
        if (!args.IsConstructCall()) {
            isolate->ThrowException(v8::String::NewFromUtf8(isolate, "CppClass 
cannot be call as function. Use 'new' to instantiate"));
            return;
        }

        CppClass* newObject = new CppClass();
        args.GetReturnValue().Set(CppClass::Wrap(newObject));
    }

    static void GetObject(v8::Local<v8::String> property, const 
v8::PropertyCallbackInfo<v8::Value>& info) {
        CppClass* obj = CppClass::Unwrap(info.Holder());
        
info.GetReturnValue().Set(obj->mJsAnotherCppClass.Get(v8::Isolate::GetCurrent()));
    }

    static void MyCppMethod_Callback(const v8::FunctionCallbackInfo<v8::Value>& 
args) {
        CppClass* obj = CppClass::Unwrap(args.This());
        args.GetReturnValue().Set(obj->MyMethod());
    }

    static v8::Persistent<v8::FunctionTemplate> functionTemplate;

private:
    AnotherCppClass* mAnotherCppClass;
    v8::Persistent<v8::Object> mJsAnotherCppClass;
};


/// Somewhere in code...

globalObjectTemplate->Set(v8::String::NewFromUtf8(isolate, "CppClass", 
v8::NewStringType::kNormal).ToLocalChecked(), CppClass::Bind());


/* ********** JavaScript code *********** */

class DerivedJsClass extends CppClass {
    constructor() {
        super();
        this.something = 1;
    }

    myJsMethod() {
        return this.something + 2;
    }
}

// With above code unmodified:
var obj = new DerivedJsClass();     // Exception: CppClass cannot be call as 
function. Use 'new' to instantiate

// When calling args.GetReturnValue().Set(args.This()) in CppClass_Constructor:
var obj = new DerivedJsClass();
console.log(obj.myCppMethod());     // prints 4
console.log(obj.myJsMethod());      // prints 3
console.log(obj.object);            // prints undefined

Reply via email to