lua 操作 C++manipulate c++ class with lua lua 操作 C++的类 ;manipulate c++ class with lua
准备弄cocos2dx的lua,捣腾一下lua,留点印记给后面的童鞋参考。(俺也是半吊子,如果看官发现啥不妥的地方,请使劲喷。我全接受)
1、版本:这是个坑。 首先 pil (programming in lua)国人(似乎是风云大大)翻译的版本是5.0 有点低了。 cocos2dx 2.15用的是lua 5.1 , 最新的lua 是5.2 , 最新的pil 3rd 也是5.2; 5.0 ;5.1; 5.2的函数变化了不少,刚接触的时候会遇到即使是copy的代码也跑错的时候,就看你的code和lua环境是否一致吧。 网上大多代码示例都是5.0的,要稍加修改。
2、看书,lua不大,也不复杂。如果不是研究lua代码实现的话,入门还是比较快的。 先把pil仔细翻几遍,对语法都ok,然后再看 C 绑定的部分。这块主要是metatable __index __newindex的几个概念搞清晰。即可。
3、c,c++ 这个其实就是用到上面(2)提到的技巧而已,本质上就是lua来通过glue代码间接操作C++的class而已。
废话不多说,赶着睡觉呢。。。。其实也说不清。看代码吧。加了详细的注释了。 makefile all: g++ -g3 -o cheneeout chenee.cpp -llua clean: rm -R *dSYM *out chenee.lua
print "test lua access C++ Class" local a = Animal("dog") --local a = Animal.creat("dog") a:setAge(100) a:sound() print ("age is :" .. a:getAge())
chenee.cpp // //@chenee:this Demo showing how to manipulate the C++ class with LUA // LUA = the moon // #include <stdio.h> #include <string> #include <iostream> extern "C"{ #include "lua.h" #include "lauxlib.h" #include "lualib.h" } //@chenee: to dump the lua stack static void stackDump(lua_State * L) { int i; int top = lua_gettop(L); /* depth of the stack */ for (i = 1; i <= top; i++) { /* repeatforeachlevel */ int t = lua_type(L, i); switch (t) { case LUA_TSTRING:{ /* strings */ printf("'%s'", lua_tostring(L, i)); break; } case LUA_TBOOLEAN:{ /* booleans */ printf(lua_toboolean(L, i) ? "true" : "false"); break; } case LUA_TNUMBER:{ /* numbers */ printf("%g", lua_tonumber(L, i)); break; } default:{ /* other values */ printf("%s", lua_typename(L, t)); break; } } printf(" "); /* put a separator */ } printf("\n"); /* end the listing */ } using namespace std; // //@chenee: the class to be deal with; // class Animal{ public: Animal(std::string name):age(0){ this->name = name;}; void setAge(int age) { this->age = age;}; int getAge(){ return this->age;}; void sound(){ cout << " -- Animal name: " << this->name << " and it's Age:"<< this->age << endl;}; private: string name; int age; }; // //@chenee: this class used as a tool to expose interfaces to lua // class LuaAnimal{ static const string className; static const luaL_reg methods[]; static const luaL_reg methods_f[]; static int creat(lua_State *L){ string name (lua_tostring(L,1)); Animal *a = new Animal(name); void **p = (void**)lua_newuserdata(L,sizeof(void*)); *p = a; luaL_getmetatable(L, className.c_str()); lua_setmetatable(L, -2); return 1; } static int gc_animal(lua_State *L) { Animal *a = (Animal*)(*(void**)lua_touserdata(L,1)); delete a; // cout << "Gc ....." << endl; return 0; } static Animal* getAnimal(lua_State *L){ luaL_checktype(L,1,LUA_TUSERDATA); void *ud = luaL_checkudata(L,1,className.c_str()); if(!ud){ luaL_typerror(L,1,className.c_str()); } return *(Animal**)ud; } static int sound(lua_State *L){ Animal *a = getAnimal(L); a->sound(); return 1; } static int setAge(lua_State *L){ Animal *a = getAnimal(L); double age = luaL_checknumber(L, 2); a->setAge(int(age)); return 0; } static int getAge(lua_State *L){ Animal *a = getAnimal(L); int age = a->getAge(); lua_pushinteger(L, age); return 1; } public: static void Register(lua_State* L) { //1: new methods talbe for L to save functions lua_newtable(L); int methodtable = lua_gettop(L); //2: new metatable for L to save "__index" "__newindex" "__gc" "__metatable" ... luaL_newmetatable(L, className.c_str()); int metatable = lua_gettop(L); //3: metatable["__metatable"] = methodtable lua_pushliteral(L, "__metatable"); lua_pushvalue(L, methodtable); lua_settable(L, metatable); // hide metatable from Lua getmetatable() //4: metatable["__index"] = methodtable lua_pushliteral(L, "__index"); lua_pushvalue(L, methodtable); lua_settable(L, metatable); //5: metatable["__gc"] = gc_animal lua_pushliteral(L, "__gc"); lua_pushcfunction(L, gc_animal); lua_settable(L, metatable); lua_pop(L, 1); // drop metatable //6: for objct: // name == 0 set object function to "methods" //eg:Animal a = Animal("xx"); //a:func() in this "methods" table; luaL_openlib(L, 0, methods, 0); // fill methodtable lua_pop(L, 1); // drop methodtable //7.1: for Class: //name = "classname" , so this set Class function to "methods_f" //eg:Animal a = Animal:creat("xx"); //Animal:creat() in this "methods_f" tables; // luaL_openlib(L, className.c_str(), methods_f, 0); //7.2: for Class: //add global function "Classname", so we Animal() is a global function now //Animal a = Animal("xx"); //function Animal()in lua will call "creat" in C++ lua_register(L, className.c_str(), creat); } }; const string LuaAnimal::className = "Animal"; const luaL_reg LuaAnimal::methods[] = { {"sound", LuaAnimal::sound}, {"setAge", LuaAnimal::setAge}, {"getAge", LuaAnimal::getAge}, {"__gc", LuaAnimal::gc_animal}, {NULL, NULL} }; const luaL_reg LuaAnimal::methods_f[] = { {"creat", LuaAnimal::creat}, {NULL, NULL} }; int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L); // LuaAnimal::Register(L); if (luaL_loadfile(L, "chenee.lua") || lua_pcall(L, 0, 0, 0)){ cout << "cannot run config. file:" << lua_tostring(L,-1) << endl; } lua_close(L); return 0; } |
|