使用C ++包装器将参数传递给Nodejs模块?

时间:2013-04-22 19:32:26

标签: node.js

我正在努力更好地理解开发使用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)

我在代码中添加了一些注释,以指出我认为问题所在。

感谢任何有关我出错的指示。

1 个答案:

答案 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 {

我还会让你的GrapesFruit拥有非默认的构造函数,这些构造函数可以像上面的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