使用訪問器訪問 C++ 對(duì)象
為我們的類設(shè)置環(huán)境
怎樣使用C++把一個(gè)類映射成為 JavaScript?首先來看看如下的例子:
//Sample class mapped to v8
class Point
{
public:
//constructor
Point(int x, int y):x_(x),y_(y){}
//internal class functions
//just increment x_
void Function_A(){++x_; }
//increment x_ by the amount
void Function_B(int vlr){x_+=vlr;}
//variables
int x_;
};
為了保證整個(gè)類映射后完全基于 JavaScript,我們對(duì)類的成員函數(shù)和變量都做映射。第一步,在上下文環(huán)境(context)中映射一個(gè)類模板:
Handle<FunctionTemplate> point_templ = FunctionTemplate::New();
point_templ->SetClassName(String::New("Point"));
從字面上似乎看出:我們只是創(chuàng)建了一個(gè)“函數(shù)(function)”模板,但實(shí)際上它能夠被看作一個(gè)類。它的名字是“Point”,我們將會(huì)在后面用到。
然后,通過訪問原型(prototype) 類模板,我們能為這個(gè)類添加內(nèi)建的方法:
Handle<ObjectTemplate> point_proto = point_templ->PrototypeTemplate();
point_proto->Set("method_a", FunctionTemplate::New(PointMethod_A));
point_proto->Set("method_b", FunctionTemplate::New(PointMethod_B));
類能通過上面的代碼“知道”它有兩個(gè)方法。但這仍然是類的原型,我們必須要實(shí)例化這個(gè)類之后,才能使用這兩個(gè)方法。
Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();
point_inst->SetInternalFieldCount(1);
SetInternalFieldCount 函數(shù)為類指針申請(qǐng)空間(在后面會(huì)再一次提到)。一旦有了類的實(shí)例,我們就能為類中的變量添加訪問器了:
point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);
至此,舞臺(tái)算是搭好了,主角該上場(chǎng)了:
Point* p = new Point(0, 0);
新類已經(jīng)建好了,但只能在C++中訪問。要對(duì)其進(jìn)行訪問,我們需要:
Handle<Function> point_ctor = point_templ->GetFunction();
Local<Object> obj = point_ctor->NewInstance();
obj->SetInternalField(0, External::New(p));
GetFunction 返回 point 的構(gòu)造器,有了它,我們可以使用 NewInstance 函數(shù)來創(chuàng)建一個(gè)新的實(shí)例。然后,使用類指針來設(shè)置內(nèi)部域(這個(gè)域的空間我們?cè)谇懊嬉呀?jīng)使用 SetInternalFieldCount 函數(shù)申請(qǐng)好了)。這樣一來,JavaScript 就能通過指針訪問該對(duì)象。
有一點(diǎn)我們漏掉了,我們想從 JavaScript 中訪問它,但只有類模板和實(shí)例,沒有名字:
context->Global()->Set(String::New("point"), obj);
最后一步將“point”這個(gè)名字和 obj 實(shí)例聯(lián)系起來。到這里,我們僅僅是完成了在腳本中使用“point”名字來創(chuàng)建 Point 類的過程。
在 JavaScript 中訪問類方法
這里講的并不是我們?cè)鯓釉?Point 類中訪問 Function_A……
先來看看回調(diào)函數(shù) PointMethod_A:
Handle<Value> PointMethod_A(const Arguments& args)
{
Local<Object> self = args.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->Function_A();
return Integer::New(static_cast<Point*>(ptr)->x_);
}
和普通的訪問器類似,我們需對(duì)參數(shù)進(jìn)行操作。而且,要能訪問我們自己的類,還必須得從內(nèi)部域中獲取相關(guān)的類指針。在將內(nèi)部域映射到“wrap”之后,就可以通過獲取它的“值(Value)”來得到類指針,然后再進(jìn)行類型轉(zhuǎn)換。得到“point”類指針之后,可以通過它來調(diào)用 method_a ,method_a 來調(diào)用回調(diào)函數(shù) PointMethod_A。
示例 v8_embedded_demo_with_object.zip (Visual C++ Express 2008 )完整的包含了上述各個(gè)步驟。
最后,我非常希望這篇文章能對(duì)你有所幫助。如果感覺文中有錯(cuò)誤或者不清楚的地方,歡迎和我進(jìn)行討論~~