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 モジュールを開発するために、スタック オーバーフローの投稿に取り組みましたが、継承されたクラスにパラメーターを追加すると、引数が基本クラスに渡されません。私は多くの解決策を試しましたが、 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;

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)

問題がどこにあると思われるかを示すために、コードにいくつかのコメントを追加しました。

私が間違っている場所についての指針に感謝します。

4

1 に答える 1

0

まず、あなたの JS 側の理解には少し誤解があると思いますが、最初にそれを解決したいと思います。

Grapes.prototype = new Fruit();

関数が2つの引数を取っFruitても、引数なしでコンストラクターを1回だけ実行するため、これについては良い方法ではありません。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 が行うように、super を呼び出すデフォルト以外のコンストラクターを作成しますGrapesFruit実装では、各Grapesオブジェクトに重量とカロリーの値があることが期待されますが、これがなければそうはなりません。Fruitまた、継承されたテンプレート関数を C++から呼び出せるようにしたい場合はUnwrapGrapesオブジェクトを として呼び出すことができる必要があり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 に答える