2013-04-22 95 views
1

我正在嘗試開發更好地理解開發使用C++包裝器的Nodejs模塊所需的技術。我正在通過儘可能多的信息進行工作,例如Nodejs Documentation。爲推動我的理解我寫設置,可以以類似的方式被用於一個模塊的NodeJS的挑戰:使用C++包裝將參數傳遞給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; 

要開發一個模塊的NodeJS與C++包裝我通過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

首先,我認爲你對事物的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實際上應該使用標準C++繼承擴展Fruit,因爲這是唯一的方式,你可以請撥打正確的super電話。

class Grapes : public Fruit { 

我也會讓你的GrapesFruit有通過調用超作爲上述JS做非默認的構造函數。你的實現需要每個Grapes對象有一個權重和卡路里值,沒有這個,情況就不會這樣。如果你希望能夠在C++中調用Fruit的繼承模板函數,那麼它需要能夠將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

+0

感謝您對我的問題的回覆。我是JS新手,因此發現你對背景中發生的事情的解釋非常有幫助。我完成了C++實現的指導,並且對JS有了更清晰的理解,一切都正常。謝謝你的幫助。 – David 2013-04-23 17:39:45