1

我正在尝试更好地理解开发使用 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发布,但是当我将参数添加到继承的类时,参数没有传递给基类。我尝试了许多解决方案,但我觉得我对Inherit(Handle parent)函数的理解是我出错的地方。代码如下:

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;

我的mod.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)

我在代码中添加了一些注释来表明我认为问题出在哪里。

感谢任何关于我哪里出错的指示。

4

1 回答 1

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扩展,因为这是您可以进行正确调用的唯一方法。FruitC++super

class Grapes : public Fruit {

我也会像上面的 JS 那样让你的Grapes并且Fruit有非默认的构造函数调用 super 。您的实现期望每个Grapes对象都有一个重量和卡路里值,如果没有这个,情况就不会如此。如果您希望能够从FruitC++ 中调用继承的模板函数,那么它需要能够UnwrapGrapes对象作为 a 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

于 2013-04-23T06:20:16.207 回答