我正在努力更好地理解开发使用C ++包装器的Nodejs模块所需的技术。我正在处理尽可能多的信息,例如Nodejs Documentation。为了理解我的理解,我设置了编写Nodejs模块的挑战,该模块可以类似的方式使用:
var addon = require('./fruit.js');
var apple = new addon.Fruit(5,7);
var pear = new addon.Fruit(3,6);
console.log("Apple: weight = " + apple.getWeight() + " calories = "
+ apple.getCalories());
var bunch = new addon.Grapes( 50, 2, 2 );
console.log("Calories of a grape: " + bunch.getCalories());
console.log("Total weight of grapes: " + bunch.getBunchWeight());
fruit.js 是:
function Fruit(weight, calories) {
this.weight = weight;
this.calories = calories;
}
Fruit.prototype.getWeight = function() {
return this.weight;
};
Fruit.prototype.getCalories = function() {
return this.calories;
};
Grapes.prototype = new Fruit();
Grapes.prototype.constructor=Grapes;
function Grapes(number, weight, calories) {
this.number=number;
this.weight=weight;
this.calories=calories;
}
Grapes.prototype.getTotalWeight = function () {
return this.number * this.weight;
}
exports.Fruit = Fruit;
exports.Grapes = Grapes;
使用C ++包装器开发Nodejs模块我通过Stack Overflow发布工作但是当我向继承类添加参数时,参数不会传递给基类。我尝试了很多解决方案,但我觉得我对继承(处理父级)函数的理解是我出错的地方。代码如下:
mymod_wrap.h
#ifndef MYOBJECT_WRAP_H
#define MYOBJECT_WRAP_H
#include <node.h>
using namespace v8;
class Fruit : public node::ObjectWrap {
public:
Fruit();
~Fruit();
static Persistent<FunctionTemplate> fruit_template;
static void Init(Handle<Object> exports);
static Handle<Value> New(const Arguments& args);
static Handle<Value> GetWeight(const Arguments& args);
static Handle<Value> GetCalories(const Arguments& args);
private:
double weight_;
double calories_;
};
class Grapes : public node::ObjectWrap {
public:
Grapes();
~Grapes();
static Persistent<FunctionTemplate> grapes_template;
static void Init(Handle<Object> exports);
static Handle<Value> New(const Arguments& args);
static Handle<Value> GetBunchWeight(const Arguments& args);
private:
int number_;
};
#endif
mymod_wrap.cc
#include <node.h>
#include "mymod_wrap.h"
using namespace v8;
Fruit::Fruit() {};
Fruit::~Fruit() {};
void Fruit::Init(Handle<Object> exports) {
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
fruit_template = Persistent<FunctionTemplate>::New(tpl);
fruit_template->InstanceTemplate()->SetInternalFieldCount(1);
fruit_template->SetClassName(String::NewSymbol("Fruit"));
NODE_SET_PROTOTYPE_METHOD(fruit_template, "getWeight", GetWeight);
NODE_SET_PROTOTYPE_METHOD(fruit_template, "getCalories", GetCalories);
exports->Set(String::NewSymbol("Fruit"), fruit_template->GetFunction());
}
Handle<Value> Fruit::New(const Arguments& args) {
HandleScope scope;
Fruit* obj = new Fruit(); // Conventional C++ Call see notes
obj->weight_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
obj->calories_ = args[1]->IsUndefined() ? 0 : args[1]->NumberValue();
obj->Wrap(args.This());
return args.This();
}
Handle<Value> Fruit::GetWeight(const Arguments& args) {
HandleScope scope;
Fruit* obj = ObjectWrap::Unwrap<Fruit>(args.This());
return scope.Close(Number::New(obj->weight_));
}
Handle<Value> Fruit::GetCalories(const Arguments& args) {
HandleScope scope;
Fruit* obj = ObjectWrap::Unwrap<Fruit>(args.This());
return scope.Close(Number::New(obj->calories_));
}
Persistent<FunctionTemplate> Fruit::fruit_template;
Grapes::Grapes() {};
Grapes::~Grapes() {};
void Grapes::Init(Handle<Object> exports) {
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
grapes_template = Persistent<FunctionTemplate>::New(tpl);
grapes_template->Inherit(Fruit::fruit_template);
grapes_template->InstanceTemplate()->SetInternalFieldCount(1);
grapes_template->SetClassName(String::NewSymbol("Grapes"));
NODE_SET_PROTOTYPE_METHOD(grapes_template, "getBunchWeight", GetBunchWeight);
exports->Set(String::NewSymbol("Grapes"), grapes_template->GetFunction());
}
Handle<Value> Grapes::New(const Arguments& args ){
HandleScope scope;
Grapes* obj = new Grapes();
obj->number_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
/* the above works but need to pass args[1], args[2] to */
/* "weight_" and "calories_" in the base class ? */
obj->Wrap(args.This());
return args.This();
}
Handle<Value> Grapes::GetBunchWeight(const Arguments& args) {
HandleScope scope;
Grapes* obj = ObjectWrap::Unwrap<Grapes>(args.This());
/* Need to unwrap the base object to get "weight_" */
/* multiply with "number_" to get the total weight of the bunch */
return scope.Close(Number::New( /* return calculated total weight */));
}
Persistent<FunctionTemplate>Grapes::grapes_template;
mymod.cc
#include <node.h>
#include "mymod_wrap.h"
using namespace v8;
void InitAll(Handle<Object> exports) {
Fruit::Init(exports);
Grapes::Init(exports);
}
NODE_MODULE(fruit, InitAll)
我在代码中添加了一些注释,以指出我认为问题所在。
感谢任何有关我出错的指示。
答案 0 :(得分:0)
首先,我认为你对JS方面的理解有一点点误解,我想先清理一下。
Grapes.prototype = new Fruit();
不是一个很好的解决方法,因为即使你的Fruit
函数有两个参数,它也会执行一次Fruit
构造函数而且只执行一次没有参数。这实际上有效
Grapes.prototype.__proto__ = Fruit;
Grapes.prototype.weight = undefined;
Grapes.prototype.calories = undefined;
你真正想要的只是第一行,就像这样完成:
var util = require('util');
util.inherits(Grapes, Fruit);
// or this if you want to do it manually.
function GrapesProto(){}
GrapesProto.prototype = Fruit;
Grapes.prototype = new GrapesProto();
构造Grapes
的调用Fruit
超级构造函数。
function Grapes(number, weight, calories) {
this.number = number;
// Call the 'super' constructor.
Fruit.call(this, weight, calories);
}
现在,尽管如此,我认为让你在C ++中使用Grapes
实际上应该使用标准Fruit
继承扩展C++
更清楚一点。这是您进行正确super
电话的唯一方式。
class Grapes : public Fruit {
我还会让你的Grapes
和Fruit
拥有非默认的构造函数,这些构造函数可以像上面的JS那样调用super。您实现期望每个Grapes
对象具有权重和卡路里值,如果没有这个值,情况就不会如此。如果您希望能够在C ++中从Fruit
调用继承的模板函数,那么它需要能够Unwrap
Grapes
对象作为Fruit
意味着它必须是一个子类。
基本上是这样的:
Handle<Value> Grapes::New(const Arguments& args ){
double weight = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
double calories = args[1]->IsUndefined() ? 0 : args[1]->NumberValue();
double number = args[2]->IsUndefined() ? 0 : args[2]->NumberValue();
Grapes* obj = new Grapes(number, weight, calories);
// AND
Grapes::Grapes(int number, double weight, double calories)
: Fruit(weight, calories), number_(number) {};
并且几乎反映了Fruit
。