例六,使用C++包装类
尽管用Lua的C API已经可以方便地写出与Lua交互的程序了,不过对于用惯C++的人来说还是更愿意用C++的方式来解决问题。于是开源社区就出现了不少Lua C API的C++的wrap,比如:LuaBind,LuaPlus,toLua
这里介绍的是LuaBind库,
它在Windows下貌似只能支持MSVC和ICC,好在Lua可以支持动态库的载入,所以用VC+LuaBind写Lua库,再用C++Builder调用也是个好主意。
在VC使用LuaBind的方法是把LuaBind的src目录下的cpp文件加入工程(
当然也可以先编译成静态库 ),加入Lua库,设置LuaBind,Lua和Boost的头文件路径。
头文件:
extern "C" { #include #include #include } #include
在C++中调用Lua函数
调用Lua函数那是最简单不过的事情了,用LuaBind的
call_function ()模板函数就可以了:
int main( lua_State *myLuaState = luaL_newstate(); luabind::open(myLuaState); luaL_dostring( myLuaState, "function add(first, second)
" " return first + second
" "end
" ); cout << "Result: " << luabind::call_function<int >(myLuaState, "add" , 2, 3) << endl; lua_close(myLuaState); }
在本例中我们先使用Lua C API产生一个Lua线程环境,然后调用
luabind::open() 让LuaBind关联这个线程环境,在使用LuaBind之前这步是必须做的,它要在Lua环境中注册一些LuaBind专用的数据。
在执行完Lua代码之后,我们使用
luabind::call_function 调用了Lua里的
add 函数,返回值是
int 。
在Lua代码中调用C++函数
从前面的文章里我们知道在Lua调用C函数需要经常操作栈,而LuaBind帮我们做了这些工作,下面的例子把
print_hello 函数送给Lua脚本调用:
void print_hello( int number) { cout << "hello world " << number << endl; } int main( lua_State *myLuaState = lua_open(); luabind::open(myLuaState); luabind::module(myLuaState) [ luabind::def("print_hello" , print_hello) ]; luaL_dostring( myLuaState, "print_hello(123)
" ); lua_close(myLuaState); }
向Lua环境加入函数或其它东东的方法是:
luabind::module(lua_State* L, char const* name = 0) [ ... ];
其中module函数中的第二个指定要加入的东东所处的名空间(
其实就是table ),如果为0,则处于全局域之下。
在中括号里的
luabind::def 把
print_hello 函数提供给Lua环境,第一个参数是Lua中使用的函数名。
如果要定义多个函数,可以使用逗号分隔。
在Lua代码中使用C++类
如果我们直接使用Lua C API向Lua脚本注册一个C++类,一般是使用
userdata+metatable 的方法,就象我们在例五中做的一样。这样做尽管难度不大,却非常繁琐而且不方便维护。
使用LuaBind我们就可以更方便地向Lua脚本注册C++类了,例:
class NumberPrinter { public : NumberPrinter(int number) : m_number(number) {} void print() { cout << m_number << endl; } private : int m_number; }; int main() { lua_State *myLuaState = lua_open(); luabind::open(myLuaState); luabind::module(myLuaState) [ luabind::class_("NumberPrinter" ) .def(luabind::constructor<int >()) .def("print" , &NumberPrinter::print) ]; luaL_dostring( myLuaState, "Print2000 = NumberPrinter(2000)
" "Print2000:print()
" ); lua_close(myLuaState); }
为了注册一个类,LuaBind提供了class_类。它有一个重载过的成员函数
def() 。这个函数被用来注册类的成员函数、操作符、构造器、枚举和属性。
它将返回
this 指针,这样我们就可以方便地直接注册更多的成员。
属性
LuaBind 也可以导出类成员变量:
template < typename T> struct Point { Point(T X, T Y) : X(X), Y(Y) {} T X, Y; }; template < typename T> struct Box { Box(Point UpperLeft, Point LowerRight) : UpperLeft(UpperLeft), LowerRight(LowerRight) {} Point UpperLeft, LowerRight; }; int main() { lua_State *myLuaState = lua_open(); luabind::open(myLuaState); luabind::module(myLuaState) [ luabind::class_float > >( "Point" ) .def(luabind::constructor<float , float >()) .def_readwrite("X" , &Point< float >::X) .def_readwrite("Y" , &Point< float >::Y), luabind::class_float > >( "Box" ) .def(luabind::constructorfloat >, Point< float > >()) .def_readwrite("UpperLeft" , &Box< float >::UpperLeft) .def_readwrite("LowerRight" , &Box< float >::LowerRight) ]; luaL_dostring( myLuaState, "MyBox = Box(Point(10, 20), Point(30, 40))
" "MyBox.UpperLeft.X = MyBox.LowerRight.Y
" ); lua_close(myLuaState); }
本例中使用
def_readwrite 定义类成员,我们也可以用
def_readonly 把类成员定义成只读。
LuaBind还可以把C++类导出成支持getter和setter的属性的Lua类:
struct ResourceManager { ResourceManager() : m_ResourceCount(0) {} void loadResource( const string &sFilename) { ++m_ResourceCount; } size_t getResourceCount() const { return m_ResourceCount; } size_t m_ResourceCount; }; int main() { lua_State *myLuaState = lua_open(); luabind::open(myLuaState); luabind::module(myLuaState) [ luabind::class_("ResourceManager" ) .def("loadResource" , &ResourceManager::loadResource) .property("ResourceCount" , &ResourceManager::getResourceCount) ]; try { ResourceManager MyResourceManager; luabind::globals(myLuaState)["MyResourceManager" ] = &MyResourceManager; luaL_dostring( myLuaState, "MyResourceManager:loadResource(\"abc.res\")
" "MyResourceManager:loadResource(\"xyz.res\")
" "
" "ResourceCount = MyResourceManager.ResourceCount
" ); size_t ResourceCount = luabind::object_cast< size_t >( luabind::globals(myLuaState)["ResourceCount" ] ); cout << ResourceCount << endl; } catch ( const std::exception &TheError) { cerr << TheError.what() << endl; } lua_close(myLuaState); }
阅读(7091) | 评论(0) | 转发(0) |