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