在你的游戏中应用Lua(3):using lua in cpp(封装栈操作)

前面提到了lua与主机程序是通过一个运行时栈来交换信息的,所以我们把对栈的访问做一下简单的封装。

我们利用从c++的函数重载机制对这些操作做封装,重载提供给我们一种以统一的方式来处理操作的机制。

向lua传递信息是通过压栈的操作来完成的,所以我们定义一些Push()函数:

inline void Push(lua_State *L, int value);
inline void Push(lua_State *L, bool value);
...

对应简单的c++内建类型,我们实现出相同的Push函数,至于函数内部的实现是非常的简单,只要利用lua提供的api来实现即可,例如:

inline void Push(lua_State *L, int value)
{
lua_pushnumber(L, value);
}

这种方式带来的好处是,在我们的代码中我们可以以一种统一的方式来处理压栈操作,如果有一种类型没有定义相关的压栈操作,将产生一个编译期错误。

后面我会提到,如何将一个用户自定义类型的指针传递到lua中,在那种情况下,我们的基本代码无须改变,只要添加一个相应的Push()函数即可。

记住close-open原则吧,它的意思是对修改是封闭的,对扩充是开放的,好的类库设计允许你扩充它,而无须修改它的实现,甚至无须重新编译。

《c++泛型设计新思维》一书提到了一种技术叫type2type,它的本质是很简单:

template <typename T>
struct type2type
{
typedef T U;
};

正如你看到的,它并没有任何数据成员,它的存在只是为了携带类型信息。

类型到类型的映射在应用于重载函数时是非常有用的,应用type2type,可以实现编译期的分派。

下面看看我们如何在从栈中取得lua信息时应用type2type:

测试类型:由于lua的类型系统与c++是不相同的,所以,我们要对栈中的信息做一下类型检测。

inline bool Match(type2type<bool>, lua_State *L, int idx)
{
return lua_type(L, idx) == LUA_TBOOLEAN;
}

类似的,我们要为cpp的内建类型提供相应的Match函数:

inline bool Match(type2type<int>, lua_State *L, int idx);
inline bool Match(type2type<const char*>, lua_State *L, int idx);

...

可以看出,type2type的存在只是为了在调用Match时决议到正确的函数上,由于它没有任何成员,所以不存在运行时的成本。

同样,我们为cpp内建类型提供Get()函数:

inline bool Get(type2type<bool>, lua_State *L, int idx)
{
return lua_toboolean(L, idx);
}

inline int Get(type2type<int>, lua_State *L, int idx)
{
return static_cast<int>(lua_tonumber(L, idx));
}

...

我想你可能注意到了,在int Get(type2type<int>)中有一个转型的动作,由于lua的类型系统与cpp的类型不同,所以转型动作必须的。

除此之外,在Get重载函数(s)中还有一个小小的细节,每个Get的函数的返回值是不相同的,因为重载机制是依靠参数的不同来识别的,而不是返回值。

前面说的都是一些基础的封装,下来我们将介绍如何向lua注册一个多参数的c函数。还记得吗?利用lua的api只能注册int (*ua_CFunction)(lua_State *)型的c函数,别忘记了,lua是用c写的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值