Chinaunix首页 | 论坛 | 博客
  • 博客访问: 225678
  • 博文数量: 56
  • 博客积分: 2480
  • 博客等级: 大尉
  • 技术积分: 475
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-28 10:57
文章分类

全部博文(56)

文章存档

2012年(36)

2011年(4)

2010年(2)

2009年(14)

我的朋友

分类: Python/Ruby

2012-03-08 10:02:55

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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++模板.

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

 

1
2
3
4
5
6
7
8
9
10
11
template
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, 1);
    lua_settable(pLuaState, LUA_GLOBALSINDEX);
}

 

使用方法很简单:

 

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

 

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

 

CallBack函数的定义如下:

 

1
2
3
4
5
6
7
8
9
10
template
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是另外一个模板函数:

 

1
2
3
4
5
6
7
8
9
template
int Call(T* pObj, RT (T::*pFunc)(P1), lua_State* pLuaState)
{
    RT result = (pObj->*pFunc)(GetValue(pLuaState, 1));
     
    PushValue(pLuaState, result);
 
    return 1;
}

 

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

 

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
template
T GetValue(lua_State* pLuaState, const int index)
{
    return T();
}
 
template<>
int GetValue(lua_State* pLuaState, const int index)
{
    return static_cast(lua_tointeger(pLuaState, index));
}
 
template<>
float GetValue(lua_State* pLuaState, const int index)
{
    return static_cast(lua_tonumber(pLuaState, index));
}
 
template<>
double GetValue(lua_State* pLuaState, const int index)
{
    return static_cast(lua_tonumber(pLuaState, index));
}
 
template<>
std::string GetValue(lua_State* pLuaState, const int index)
{
    return std::string(lua_tostring(pLuaState, index));
}
 
//----------------------------------------------------------------------------------------------
 
template
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函数都不一样, 这同时带来了许多限制. 不过暂时用不到太多的数据类型.

 

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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++代码中, 就能看到想要的结果了.

 

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

阅读(928) | 评论(0) | 转发(0) |
0

上一篇:lua c++ 1

下一篇:Userdata 使用

给主人留下些什么吧!~~