文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Lua学习笔记(十五)

Lua学习笔记(十五)

时间:2010-09-11  来源:glshader

先写一个类, 没有什么意义, 测试用一下:

 

class MyClass
{
public:
        int add(int n)
        {
                return n + m_n;
        }

        int Foo2(int n)
        {
                return n*m_n;
        }

public:
        int m_n;
};

 

 

我创建MyClass的实例, 向Lua注册一个函数Func, 将实例和MyClass成员函数与Func绑定到一起. 当Lua代码调用Func的时候, 成员函数被调用. 这点需求折腾了我半天, 现在终于找到该怎么搞定了.

解决办法就是用C++模板.

让我们先来看一下注册函数:

 

template<typename T, typename TFunc>
void RegisterMemberFunc(lua_State* pLuaState, const char* pszName, T* pObj, TFunc pFunc)
{
        lua_pushstring(pLuaState, pszName);

        char* pData = (char*)lua_newuserdata(pLuaState, sizeof(T*) + sizeof(TFunc));
        memcpy(pData, &pObj, sizeof(T*));
        memcpy(pData + sizeof(T*), &pFunc, sizeof(TFunc));
        lua_pushcclosure(pLuaState, &CallBack<T, TFunc>, 1);
        lua_settable(pLuaState, LUA_GLOBALSINDEX);
}

 

使用方法很简单:

 

RegisterMemberFunc(pLuaState, "Add", &m, &MyClass::add);

 

在这个函数中, 我们创建了一个userdata, 用于保存实例地址, 成员函数地址, 并且在pushcclosure时, 将userdata和Add函数绑定.

 

CallBack函数的定义如下:

 

template<typename T, typename TFunc>
int CallBack(lua_State* pLuaState)
{
        char* pData = (char*)lua_touserdata(pLuaState, lua_upvalueindex(1));

        T*         pObj  = *(T**)(pData);
        TFunc* pFunc = (TFunc*)(pData + sizeof(T*));

        return Call(pObj, *pFunc, pLuaState);
}

 

在这个回调函数中, 用 lua_upvalueindex获取存储在当前函数中的userdata, 里面就是我们保存的实例地址和成员函数地址. 获得必要的信息以后, 调用Call进行实际的操作.

 

 

Call是另外一个模板函数:

 

template<typename T, typename RT, typename P1>
int Call(T* pObj, RT (T::*pFunc)(P1), lua_State* pLuaState)
{
        RT result = (pObj->*pFunc)(GetValue<P1>(pLuaState, 1));
        
        PushValue(pLuaState, result);

        return 1;
}

 

这个辅助函数用于解析成员函数的返回值, 参数类型. 为了节约篇幅, 我紧紧写出了只有一个参数的情况, 根据需求的不同, 我们可以编写更多个参数的情况, 另外, 在这里, 成员函数返回值类型不能为void.

 

GetValue, PushValue, 是两套模板函数, 用于对不同的参数类型进行不同的操作:

 

template<typename T>
T GetValue(lua_State* pLuaState, const int index)
{
        return T();
}

template<>
int GetValue(lua_State* pLuaState, const int index)
{
        return static_cast<int>(lua_tointeger(pLuaState, index));
}

template<>
float GetValue(lua_State* pLuaState, const int index)
{
        return static_cast<float>(lua_tonumber(pLuaState, index));
}

template<>
double GetValue(lua_State* pLuaState, const int index)
{
        return static_cast<double>(lua_tonumber(pLuaState, index));
}

template<>
std::string GetValue(lua_State* pLuaState, const int index)
{
        return std::string(lua_tostring(pLuaState, index));
}

//----------------------------------------------------------------------------------------------

template<typename T>
void PushValue(lua_State* pLuaState, T)
{

}

template<>
void PushValue(lua_State* pLuaState, int nValue)
{
        lua_pushinteger(pLuaState, (lua_Integer)nValue);
}

template<>
void PushValue(lua_State* pLuaState, float fValue)
{
        lua_pushnumber(pLuaState, (lua_Number)fValue);
}

template<>
void PushValue(lua_State* pLuaState, double dValue)
{
        lua_pushnumber(pLuaState, (lua_Number)dValue);
}

template<>
void PushValue(lua_State* pLuaState, const char* psz)
{
        lua_pushstring(pLuaState, psz);
}

 

这里, 不得不编写模板的特例, 因为各种类型对应的Lua函数都不一样, 这同时带来了许多限制. 不过暂时用不到太多的数据类型.

 

现在, 我们将一切穿插起来:

 

   lua_State* pLuaState = luaL_newstate();
        luaL_openlibs(pLuaState);

        MyClass m;
        m.m_n = 100;
        RegisterMemberFunc(pLuaState, "Add", &m, &MyClass::add);
        if (luaL_loadfile(pLuaState, "test.lua") ||
                lua_pcall(pLuaState, 0, 0, 0))
        {
                // something wrong
                printf("something wrong\n");
        }

        lua_close(pLuaState);

 

在test.lua中, 我们编写如下代码:

并且调进C++代码中, 就能看到想要的结果了.

 

但是到这里, 还远远不够.

相关阅读 更多 +
排行榜 更多 +
打螺丝高手

打螺丝高手

模拟经营 下载
解救火柴人计划安卓版

解救火柴人计划安卓版

体育竞技 下载
鸡生化精英安卓版

鸡生化精英安卓版

飞行射击 下载