luabind
lua是一个内嵌式的语言,很多初学者对于lua中使用c++类中的函数,或者用c++直接创建一个自己的自定义数据类型比较头疼,因为这部分确实比较乱,牵扯到内存释放分配等问题,但是如果把其中关系理清,还是很简单的,下面这段代码是一个老外写的,我做了一些修改。首先看代码。
- #ifndef LUNA_H
- #define LUNA_H 1
- /****************************************************************************
- * This program is free software. It comes without any warranty, to *
- * the extent permitted by applicable law. You can redistribute it *
- * and/or modify it under the terms of the Do What The Fuck You Want *
- * To Public License, Version 2, as published by Sam Hocevar. See *
- * http://sam.zoy.org/wtfpl/COPYING for more details. *
- ****************************************************************************/
- /******************************************************************************
- * 这是一个自由传播修改的文件,如果你够厚道就保留下我的签名吧 *
- * Edit by fox *
- * 2010-4-13 *
- * http://blog.youkuaiyun.com/limiteee *
- ******************************************************************************/
- // convenience macros
- //注册一个自定义类型,并用该类名创建一个元表
- #define luna_register(L, klass) (Luna<klass>::Register((L)))
- //注册一个自定义数据类型,并用该类名创建一个元表,该类必须是一个Ogre::Singleton的派生类,一般用于lua访问c环境中全局唯一实例的类
- #define luna_register_singleton(L, klass) (Luna<klass>::Register_singleton((L)))
- #define luna_registermetatable(L, klass) (Luna<klass>::RegisterMetatable((L)))
- #define luna_inject(L, klass, t) (Luna<klass>::inject((L), (t)))
- #define luna_flag_meta_func 0
- #define luna_flag_func 1
- /*
- ----------------------------------------------------------------------------------------------------------
- LUNA_CLASS_D_DEFAULT_VALS 需要写在类声明中
- LUNA_CLASS_D_INIT_VALS_CLASSNAME 写在类实现中
- LUNA_CLASS_D_INIT_VALS_FUNCNAME_START 开始进行lua声明,必须以这个宏开始
- LUNA_CLASS_D_INIT_VALS_FUNCNAME_END lua声明结束,必须以这个宏结束
- LUNA_CLASS_D_INIT_VALS_FUNCNAME_USER 进行用户自定义函数的lua声明
- LUNA_CLASS_D_INIT_VALS_META_FUNCNAME_USER 定义一个元表的方法
- LUNA_CLASS_D_INIT_VALS_META_FUNCNAME_ALIAS_USER 定义一个元表的方法,并且使用指定的别名
- BUILD_LUACLASS 在lua中创建一个指定类的自定义数据,new一个该类指针赋予这个自定义数据
- BUILD_LUACLASS_LP 在lua中创建一个指定类的自定义数据,使用一个已经存在的该类指针赋予这个自定义数据
- cLinkName 可以是任何类,没有规定,这个类只是给lua类进行访问的。
- cName 是lua类,这个类将可以在lua中访问
- ----------------------------------------------------------------------------------------------------------
- */
- #define LUNA_CLASS_D_DEFAULT_VALS(cName,cLinkName) /
- public: /
- static cLinkName *m_pLink; /
- static const char className[]; /
- static const Luna<cName>::RegType Register[];
- #define LUNA_CLASS_D_INIT_VALS_CLASSNAME(cName,cLinkName) /
- cLinkName *cName::m_pLink = 0; /
- const char cName::className[] = #cName;
- #define LUNA_CLASS_D_INIT_VALS_CLASSNAME_ALIAS(cName,cLinkName,Alias) /
- cLinkName *cName::m_pLink = 0; /
- const char cName::className[] = Alias;
- #define LUNA_CLASS_D_INIT_VALS_FUNCNAME_START(cName) /
- const Luna<cName>::RegType cName::Register[] = {
- #define LUNA_CLASS_D_INIT_VALS_FUNCNAME_USER(fName,cName) /
- {#fName,&cName::fName},
- #define LUNA_CLASS_D_INIT_VALS_FUNCNAME_ALIAS_USER(fName,cName,Alias) /
- {Alias,&cName::fName},
- #define LUNA_CLASS_D_INIT_VALS_FUNCNAME_END { 0 }};
- #define LUNA___INDEX_FUNCTION -1
- #define BUILD_LUACLASS(ClassName, L) Luna<ClassName>::constructor( L )
- #define BUILD_LUACLASS_LP(ClassName, L, ClassPtr) Luna<ClassName>::constructor_lightptr( L, ClassPtr );
- //
- //extern "C" {
- //#include "lua.h"
- //#include "lualib.h"
- //#include "lauxlib.h"
- //}
- #include "lua.hpp"
- template<class T> class Luna {
- public:
- //注册唯一实例的对象------------------------------------------------------------------------------------------------------------------------------------------------
- static void Register_singleton(lua_State *L) {
- const char* cn = T::className;
- lua_pushcfunction(L, &Luna<T>::constructor_singleton);
- lua_setglobal(L, T::className); // T() in lua will make a new instance.
- }
- //使用一个c环境中已存在的指针创建一个自定义数据,该指针需要c来释放,这个方法没有注册gc函数
- static int constructor_lightptr(lua_State *L, T* obj) {
- return inject_singleton(L, obj);
- }
- //使用一个Ogre::Singleton的派生类的指针创建一个自定义数据,该指针需要c来释放,这个方法没有注册gc函数
- static int constructor_singleton(lua_State *L) {
- return inject_singleton(L, static_cast<T*>(T::getSingletonPtr()));
- }
- static int inject_singleton(lua_State *L, T* obj) {
- //创建一个自定义数据,返回一个指向指针的指针,这里不使用light udata是因为我们需要lua为我们管理内存回收
- T** a = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
- *a = obj; // 指针的指针赋值
- const char *cn = T::className;
- int rt = luaL_newmetatable(L, T::className); // get (or create) the unique metatable
- if ( rt )
- {
- //设置一个默认的__index函数
- lua_pushstring(L, "__index");
- lua_pushnumber(L, LUNA___INDEX_FUNCTION);
- lua_pushcclosure(L, &Luna<T>::thunk, 1);
- lua_settable(L, -3);
- //-----------------------------------------------------------------------
- //为元表添加方法
- for (int i = 0; T::Register[i].name; i++) { // register the functions
- lua_pushstring(L, T::Register[i].name);
- lua_pushnumber(L, i); // let the thunk know which method we mean
- lua_pushcclosure(L, &Luna<T>::thunk, 1);
- lua_settable(L, -3); // self["function"] = thunk("function")
- }
- }
- //-----------------------------------------------------------------------
- lua_setmetatable(L, -2); //将自定义数据的元表设置为刚刚创建的表
- return 1;
- }
- //这里注册可自动回收的对象---------------------------------------------------------------------------------------------------------------------
- static void Register(lua_State *L) {
- const char* cn = T::className;
- lua_pushcfunction(L, &Luna<T>::constructor);
- lua_setglobal(L, T::className); // T() in lua will make a new instance.
- }
- static int constructor(lua_State *L) {
- return inject(L, new T(L));
- }
- static int inject(lua_State *L, T* obj) {
- //创建一个自定义数据,返回一个指向指针的指针,这里不使用light udata是因为我们需要lua为我们管理内存回收
- T** a = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
- *a = obj; // 指针的指针赋值
- const char *cn = T::className;
- int rt = luaL_newmetatable(L, T::className); // get (or create) the unique metatable
- if ( rt )
- {
- //设置一个默认的__index函数
- lua_pushstring(L, "__index");
- lua_pushnumber(L, LUNA___INDEX_FUNCTION);
- lua_pushcclosure(L, &Luna<T>::thunk, 1);
- lua_settable(L, -3);
- //设置自动销毁函数
- lua_pushstring(L, "__gc");
- lua_pushcfunction(L, &Luna<T>::gc_obj);
- lua_settable(L, -3); // metatable["__gc"] = Luna<T>::gc_obj
- //-----------------------------------------------------------------------
- //为元表添加方法
- for (int i = 0; T::Register[i].name; i++) { // register the functions
- lua_pushstring(L, T::Register[i].name);
- lua_pushnumber(L, i); // let the thunk know which method we mean
- lua_pushcclosure(L, &Luna<T>::thunk, 1);
- lua_settable(L, -3); // self["function"] = thunk("function")
- }
- }
- //-----------------------------------------------------------------------
- lua_setmetatable(L, -2); //将自定义数据的元表设置为刚刚创建的表
- return 1;
- }
- static int thunk(lua_State *L) {
- // redirect method call to the real thing
- int d = lua_gettop(L);
- int i = (int)lua_tonumber(L, lua_upvalueindex(1)); // which function?
- T** obj = static_cast<T**>(luaL_checkudata(L, 1, T::className)); //第一个参数就是他自己
- //察看第二个参数是什么
- int iType = lua_type(L, 2);
- if (iType == LUA_TSTRING) {
- //如果第二个参数是字符型,那么它可能是一个call调用
- int rt = call_obj(L);
- //如果调用发现同名函数那么执行它,并且返回
- if ( rt ) {
- return rt;
- }
- }
- //每次调用使用的是目标对象来调用,所以函数访问的内部变量就是他自己的
- return ((*obj)->*(T::Register[i].mfunc))(L); // execute the thunk
- }
- static int call_obj(lua_State *L) {
- int d = lua_gettop(L);
- T** obj = static_cast<T**>(luaL_checkudata(L, 1, T::className)); //第一个参数就是他自己
- const char* funcname = lua_tostring(L, 2);
- for (int i = 0; T::Register[i].name; i++) {
- if( strcmp( funcname, T::Register[i].name ) == 0 ) {
- //找到这个函数,并且返回它
- lua_pushnumber(L, i); // let the thunk know which method we mean
- lua_pushcclosure(L, &Luna<T>::thunk, 1);
- return 1;
- }
- }
- return 0;
- }
- static int gc_obj(lua_State *L) {
- // clean up
- //printf("GC called: %s/n", T::className);
- T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
- delete (*obj);
- return 0;
- }
- struct RegType {
- const char *name;
- int(T::*mfunc)(lua_State*);
- };
- };
- #endif /* LUNA_H */