同python不同, LUA并没那么庞大也没提供众多的功能库,适合做相对对立的系统而非整个应用。LUA官方版本只包括一个精简的核心和最基本的库。这使得它体积小、启动速度快,从而适合嵌入在别的程序里同时也方便移植。5.0版本以前的LUA对面向对象支持不多,这个始于1993年的产物核心思想是用虚拟栈作为与宿主语言交互的手段,所以主流的封装方式还是以注册函数为主。但能直接对对象操作一直作为高级语言的一个特征,所以不少lua的第三方库以对象化封装作为扩充lua的封装方式,有代表性的是 LuaPlus LuaBind toLua++ LuaTinker。 其中我觉得最能体现lua 精简精髓的应该是luatinker,原因无他,就一个.h和cpp文件。 不像其他的有借助boost这种庞大的库来实现一个对原本袖珍的lua库进行扩展的。所以接下来的讨论依然围绕luatinker对这种方式的实现为主。
从下面列举的一一对应来看看lua是如何一步步向C++的类迈进的
C++ | LUA |
Class | Table |
this | lightuserdata |
Member data | metatable |
Member function | metatable |
Virtual Member function | metatable |
转换前的基础
Table做为lua对数据集合的表述手段,其地位也正如class在C++中的一样,多半用户定义的数据都是它。简单来看 表名 和类名 ,表项和 类成员数据,成员方法(lua的表项可以是数据也可以是function,key对应的名字而val就是真正的函数) 很多都感觉很像,那么作为ood的第一步,让lua中使用对象的载体,Table无疑是是最适合的(其实在lua中也没有太多其他类型可选)
Class-> Table
__index 事件: 对应脚本: 和 []词法
__index事件的元方法(metamethod)一般作为对象成员函数的调用标,如 player:levelup(2) 其返回值为通过函数名(key)取到的对象调用的成员函数,这块在有继承关系的class上需要额外实现一套递归查询的方法
__newindex 事件: 对应脚本中对: 和 []操作项赋新值
__gc事件: 对应class 的析构函数
__call事件:对应class 的构造函数
* 该Table会作为所有此类型的class变量 在lua环境中对应 lightuserdata 的 metatable,因为metatable可以嵌套,所以该metatable的事件会自然为lightuserdata所用
this->data
class A {int m_nN1; float m_fSpeed;}
float A::*pfl = &A:: m_fSpeed;
A a1; a1.*pfl = 0.5f;
- 把a1的地址作为lightuserdata 的val 传入LUA
- 把pfl 及其对应的string-key “Speed”传入LUA
- 当脚本中调用user:Speed 的时候通过lightuserdata上的metatable映射成宿主语言 (&a1)->pfl
- 通过push和pop操作将宿主对象的值传入或赋值
this-> function
class A{
const char* name(int a)
{ return “cos”;}
}
const char* (A::*pfunc)();
pfunc = &A::name;
A a2;
(a2.*pfunc )(11);
老办法,先传数据再传递需要调用的函数地址
- 把a2的地址作为lightuserdata 的val 传入LUA
- 把pfunc及其对应的string-key “Name”传入LUA
- 当脚本中调用user. Name 的时候通过lightuserdata上的metatable映射成宿主语言 (&a2)->pfunc
- 根据function 的参数调用等次数的 push 和区分返回值是否为void调用0次或1次pop
this-> virtual function
class A{
virtual const char* name(int a)
{return “class a”;}
}
class B: public A {
const char* name(int a)
{return “class b”;}
}
const char* (A::*pfunc)();
pfunc = &A::name;
B b1; (b1.*pfunc )(11);
- 把a2的地址作为lightuserdata 的val 传入LUA
- 把pfunc及其对应的string-key “Name”传入LUA
- 当脚本中调用user. Name 的时候通过lightuserdata上的metatable映射成宿主语言 (&a2)->pfunc
- 根据function 的参数调用等次数的 push 和区分返回值是否为void调用0次或1次pop
Inherit