Io 程式設計/將 Io 繫結到 C++
外觀
< Io 程式設計
以下程式碼示例展示了一個簡單的繫結到 Io 的類。繫結已透過測試,但可能不完全正確。
IoBindingTest 類只儲存一個數字,並提供通常的 setter 和 getter 訪問器。此外,可以比較兩個類的例項。該類具有常規的建構函式,以及一個複製建構函式和一個接受數字的建構函式。在繫結中建立克隆時使用複製建構函式。
// begin test class
class IoBindingTest;
class IoBindingTest
{
public:
IoBindingTest() : num(0) {};
IoBindingTest(int n) : num(n) {};
IoBindingTest(IoBindingTest* ptr) : num(ptr->num) {};
~IoBindingTest() {};
int GetNum(void) { return num; };
void SetNum(int n) { num = n; };
bool CompareWith(IoBindingTest* obj) { return num == obj->num; };
private:
int num;
};
// end test class
繫結類建立了一堆靜態類函式,這些函式可以從 C 程式碼(如 Io 的 VM)訪問,用於使用測試類的同名例項方法。此外,繫結類還具有特定於 Io VM 的方法(proto、tag、rawClone、mark、free),以及一個在執行時將繫結新增到 VM 的最終函式。
#include "IoVM.h"
class IoBindingTest_io
{
public:
static IoObject* GetNum(IoObject *self, IoObject *locals, IoMessage *m);
static IoObject* SetNum(IoObject *self, IoObject *locals, IoMessage *m);
static IoObject* CompareWith(IoObject *self, IoObject *locals, IoMessage *m);
static IoObject* proto(IoState* state);
static IoTag* tag(IoState* state, const char* name);
static IoObject* rawClone(IoObject* self);
static IoObject* mark(IoObject* self);
static IoObject* free(IoObject* self);
static void addBinding(IoState* state);
};
IoTag *IoBindingTest_io::tag(IoState* state, const char* name)
{
IoTag* tag = IoTag_newWithName_(name);
tag->state = state;
tag->cloneFunc = (TagCloneFunc*) rawClone;
tag->markFunc = (TagMarkFunc*) mark;
tag->freeFunc = (TagFreeFunc*) free;
return tag;
}
proto 函式用於在 Io VM 中建立初始原型。
IoObject *IoBindingTest_io::proto(IoState* state)
{
IoMethodTable methods[] = {
{"GetNum", GetNum},
{"SetNum", SetNum},
{"CompareWith", CompareWith},
{NULL, NULL}
};
IoObject* self = IoObject_new(state);
self->tag = tag(state, "IoBindingTest");
self->data = 0;
IoObject_addMethodTable_(self, methods);
return self;
}
addBinding 函式用於在執行時將我們物件的原型放入 Io VM 中。
void IoBindingTest_io::addBinding(IoState* state)
{
IoObject* self = proto(state);
IoState_registerProtoWithFunc_(state, self, (IoStateProtoFunc*)proto);
IoObject_setSlot_to_(state->lobby, IOSYMBOL("IoBindingTest"), self);
}
IoObject *IoBindingTest_io::rawClone(IoObject *self)
{
IoObject *clone = IoObject_rawClonePrimitive(self);
if (self->data)
clone->data = new IoBindingTest(reinterpret_cast<IoBindingTest*>(self->data));
else
clone->data = new IoBindingTest;
return clone;
}
mark 函式由垃圾收集器使用。如果 C++ 物件引用了 Io VM 中的其他物件,則也必須標記這些物件。
IoObject *IoBindingTest_io::mark(IoObject *self)
{
return self;
}
free 顧名思義,這是在適當的情況下釋放/刪除 C++ 物件的地方。
IoObject *IoBindingTest_io::free(IoObject *self)
{
if (self->data)
{
IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
delete obj;
self->data = NULL;
}
return self;
}
以下三個函式是例項方法的實際繫結,因此可以從指令碼中呼叫它們。
IoObject* IoBindingTest_io::GetNum(IoObject *self, IoObject *locals, IoMessage *m)
{
IOASSERT(self->data, "No C++ object");
IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
return IoNumber_newWithDouble_(self->state, obj->GetNum());
};
IoObject* IoBindingTest_io::SetNum(IoObject *self, IoObject *locals, IoMessage *m)
{
IOASSERT(self->data, "No C++ object");
IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
IOASSERT(IoMessage_argCount(m) == 1, "Wrong number of arguments");
IoObject *arg1 = IoMessage_locals_numberArgAt_(m, locals, 0);
obj->SetNum(IoNumber_asInt(arg1));
return self;
};
IoObject* IoBindingTest_io::CompareWith(IoObject *self, IoObject *locals, IoMessage *m)
{
IOASSERT(self->data, "No C++ object");
IoBindingTest* obj = reinterpret_cast<IoBindingTest*>(self->data);
IOASSERT(IoMessage_argCount(m) == 1, "Wrong number of arguments");
IoObject *arg1 = IoMessage_locals_valueArgAt_(m, locals, 0);
// make sure the object is tagged
IOASSERT(arg1->tag, "No tag in arg");
// check the tag to make sure it is the right object class
IOASSERT(strcmp(arg1->tag->name, "IoBindingTest") == 0, "arg not IoBindingTest object");
// check for the actual existence of the C++ object
IOASSERT(arg1->data, "No C++ object in arg");
IoBindingTest* arg1obj = reinterpret_cast<IoBindingTest*>(arg1->data);
// bool is simulated by returning self or nil
if (obj->CompareWith(arg1obj))
return self;
else
return IONIL(self);
};