lua(三)面向对象思想

1 篇文章 0 订阅
1 篇文章 0 订阅
Table的使用,面向对象思想

(关于table在lua脚本中的定义以及语法,不做介绍,baidu以及google非常多。本文将介绍,lua在C++面向对象思想的应用)

一(metatable)

lua的metatable的官方解释,

1. 每个table和每个full user data都可以有自己的metatable,并可通过setmetatable和getmetatable进行访问
2. 其他任何lua类型,每种类型共享一个metatable;比如number类型共享一个metatable;string类型共享一个metatable;这些类型的metatable无法更改,除非用C API
3. metatable的key叫事件(event),value叫元方法(metamethod)
4. 除了__index,__newindex可以是function或table外,其他元方法都必须是function

举个例子说明,对于一个非数值类型的值,我们可以修改元表里的"__add"字段里的函数,来定义其加法的行为。这样,对该类型值进行加法运算,就会自动调用__add对应的元方法。            如果调用该类型一个未定义的key或者未注册的函数,就会查找__index事件。等等。

 

二(C++中类的成员函数)

类,是某些类型的集合体,即,内存块。所有的类成员地址,相对于类对象首地址都有一定的便宜量,尽管你声明成protected或者private,也可以根据偏移量得到该成员。(懂汇编语言的,这句话不难理解)。类成员函数,他相对于所有的类对像,地址是相同的,可以理解成他是类的静态成员。也可以理解成某种特殊意义的表。

举例说明,某个类C1成员函数Fn,计算两个数相加,可以得到以下汇编代码:

//  C1 a;

_asm

{

mov eax, dword ptr[y];

push eax;       // 参数压栈

mov eax, dword ptr[x];

push eax;      // 参数压栈

lea ecx, [a];    // ecx保存变量a的地址

call C1::Fn;   // 调用成员函数

}  (这里仅仅列举一种情况,对于不同类型的C++函数,对应的汇编代码不相同,比如使用__stdcall声明的函数)

 

三(面向对象思想在lua脚本中的应用)

Win32窗口API中,每个函数都有HWND窗口句柄参数,可以理解成这个参数就是我们的“窗口类对象”。所以,可以模拟这样的函数实现lua脚本的面向对象应用。

例如,

l=CreateLine();

l.Initialize(l, 0, 0, 100, 100);

l.SetColor(l, 0);

该脚本意思是说,绘制0,0到100,100的一条黑色直线。不过每次都传递 l 参数,太麻烦了。好在,lua脚本有:(冒号)操作符,l.Initialize(l, 0, 0, 100, 100);等同于l:Initialize(0, 0, 100, 100);这样就如同C++中调用类成员函数一样。

 

四(举例说明)

还是拿上面划线的例子说明:(看半天理论,不如看一行代码。如同使用图的表达方式比文字表达方式快一样)

[In  C++]

class CLine

{

public:

    void Initialize(int bx, int by, int ex, int ey);

}

 

int lua_LineInitialize(lua_State* L)

{

    if (lua_gettop(L) < 5)

        return 0;

 

    lua_getfield(L, 1, "inskey");

    int bx = luaL_checkint(L, 2);

    int by = luaL_checkint(L, 3);

    int ex = luaL_checkint(L, 4);

    int ey = luaL_checkint(L, 5);

    DWORD_PTR dwLine = luaL_checkint(L, -1);

    reinterpret_cast<CLine*>(dwLine)->Initialize(bx, by, ex, ey);

 

    return 0;

}

 

// int lua_LineSetColor(lua_State* L);

 

int lua_CreateLine(lua_State* L)

{

    static bool bHasInit = false;

    if (!bHasInit)

    {

        bHasInit = true;

 

        lua_newtable(L);                         // 定义操作函数表

        lua_pushvalue(L, -1);

        lua_setfield(L, -2, "__index");    // __index指向table(自己)

        lua_pushcfunction(L, lua_LineInitialize);

        lua_setfield(L, -2, "Initialize");

        lua_pushcfunction(L, lua_LineSetColor);

        lua_setfield(L, -2, "SetColor");

        lua_setglobal(L, "MetaLine");

    }

 

    CLine* p = new CLine;

 

    lua_newtable(L);

    lua_pushnumber(L, (DWORD_PTR)p);

    lua_setfield(L, -2, "inskey");        // 保存CLine指针对象为inskey

    lua_getglobal(L, "MetaLine");

    lua_setmetatable(L, -2);             //  为新创建的table设置操作函数表,即,设置名称为MetaLine的 metatable.

 

    return 1;                                         // 一个返回值,table

}

 

// 注册代码,省略。。。

// lua_register(L, "CreateLine", lua_CreateLine);

 

[In lua]

l=CreateLine();

l:Initialize(0, 0, 100, 100);

l:SetColor(0);

(感觉是否在写C++程序呢?)

五(说明)

lua中,每个table都是不同的类型,所以为不同的table设置不同的metatable,不会搞乱。网上有的例子,使用luaL_ref(L, LUA_REGISTRYINDEX)函数得到一个注册key,该key为数据类型,然后设置该key的metatable为MetaLine,这样就为lua所有的数据类型设置了metatable。那么,我如果再定义一个Rect类型,再次注册得到一个数据类型的key,然后设置该key的metatable为MetaRect,又把所有的数据类型重新设置了一次metatable,这样,刚刚定义的line就不能调用line的方法了,因为数据类型的metatable已经为rect的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值