研究SLB也有段时间了,很喜欢这个库,轻巧、紧凑、不依赖任何第三方库。SLB支持杂交类,就是可以让你在C++类中调用Lua的函数,并完全将其当作类成员函数来使用。支持继承以及多重继承,支持构造函数。最为有特色的是其对__index,__newindex元方法的暴露使我们有更多的灵活性。而有点遗憾的是,相对于其他成熟的lua库(例如luabind、luaplus)来说,他不支持类成员变量的绑定。我想库的作者Jose L. Hidalgo的本意是不想让我们对类成员变量进行绑定,要么就是认为__index和__newindex原方法的设置可以完全实现我们的要求。不过对我来说总归是不方便,所以自己实现了一些代码,将类成员的绑定做了实现。
首先我写了两个类,用于对类成员变量分别做set和get的操作。
这两个类都是模板函数,继承于FuncCall模板参量分别描述了类的类型以及成员变量的类型。并将类成员变量相对与类的偏移量作为变量保存与Members系列类中。listener是作为监听器存在的,目的在于为变量被更改的时候给宿主类一个通知。
之后,我在Table函数里实现了具体的绑定代码
这段代码将两个object对象存储在ClassInfo类中的__members子表中,这两个object对象分别为getMember,setMember模板类的实例化对象。
建立子表是为了区别通过set建立的成员函数对象,使之不发生混淆。
下来我们将实现调用这setMember和getMember对象的代码,从而使你在写出class.member = 10之类的代码的时候SLB可以正确的执行。
我将Table::__index函数做了一些修改,现在的__index看起来是这样的
这里我们通过Key( lua_tostring(L,2) )来找到我们保存的object对象。如果找不到我们再到__members子表里去找。如果找到了我们就将这个对象压栈,然后将其插入到堆栈编号为1的位置,之后的堆栈看起来就是 func, key, value 这时通过调用lua_call让lua自己调用object所指的函数对象,也就是( getMember< C, V > );
如果我们做了继承类的设定,那么当我们要访问父类的成员变量的时候,这点代码是无法完成我们的要求的。所以我又修改了ClassInfo::__index的代码。改完之后的代码如下
我只是在继承类的映射表里搜索了一遍,并逐个查找其__members子表,其他的跟Table::__index所使用的方法是一样的。
getMember的调用方法到这里就可以使用了。接下来我修改了ClassInfo::__newindex 使其在恰当的时机调用setMember的Call函数修改后的代码如下:
好了终于完成了部署,现在只差最后一步。实现Class类的member
template< class C, typename V >
__Self &member( const char *name, V C::* offset, void (C::* set)() = NULL, void (C::* get)() = NULL )
{
_class->member( name, offset, set, get );
return *this;
}
好了,我们现在可以写出如下的代码了
Class< SpriteAttribute >( "ui::SpriteAttribute" )
.constructor< _string, float, float, float, float >()
.member( "f", &SpriteAttribute::path )
.member( "x", &SpriteAttribute::x )
.member( "y", &SpriteAttribute::y )
.member( "w", &SpriteAttribute::w )
.member( "h", &SpriteAttribute::h )
.set( "members",&show_members< SpriteAttribute > )
.set( "save", &save_file< SpriteAttribute > )
.set( "load", &load_file< SpriteAttribute > )
;
是不是很酷?
另外SLB还有些小缺陷在他的Type.hpp中,我也做了修改和补充。代码我就直接贴在下面了,具体有什么不同留给你们自己看吧。提示一下,有一些const 类型原先是没有的,另外我加了对wstring的支持。