主要是针对网上的一份代码自己的理解注释,下面就直接贴代码了。
//LuaCPP.h
#include<lua.hpp>
class CTest
{
public:
//带一个参数的构造函数
CTest(int value):m_value(value){};
virtual ~CTest(){};
//进行加操作
int Add(int x,int y)
{
printf("%p Add:x=%d,y=%d\n",this,x,y);
return x + y;
}
//访问类成员
void PrintValue()
{
printf("Value = %d\n",m_value);
}
private:
int m_value;
};
//导出一个函数到Lua,用于创建C++类
static int CreateCTest(lua_State* L)
{
//取出构造函数参数
int nValue = lua_tointeger(L,1);
//创建一个CTest对象并把它的指针通过用户数据方式传递给lua
//这是对userdata的说明:
//A full userdata represents a block of memory.
//It is an object (like a table): you must create it, it can have its own metatable
*(CTest**)lua_newuserdata(L,sizeof(CTest*)) = new CTest(nValue);
//从注册表中找到CTest元表并压入栈顶
luaL_getmetatable(L, "CTest");
//将CTest元表作为用户数据的元表(由于对函数还不熟悉,开始理解成把userdata赋给CTest呢,哈哈)
lua_setmetatable(L,-2);
//该函数调用后栈里就是一个userdata了。
return 1;
}
static int DestoryCTest(lua_State* L)
{
//释放对象
delete *(CTest**)lua_topointer(L,1);
return 0;
}
static int CallAdd(lua_State* L)
{
//调用C++类方法的跳板函数,此处其实有个陷阱
//lua_topointer返回的其实是CTest**,由于此处不涉及到
//类的数据成员操作,无所谓我就没有改了
CTest* pT = (CTest*)lua_topointer(L,1);
lua_pushnumber(L, pT->Add(lua_tonumber(L,2),lua_tonumber(L,3)));
return 1;
}
static int CallPrint(lua_State* L)
{
//这样才能给找到真正的对象
CTest** pT = (CTest**)lua_topointer(L,1);
//打印成员变量的值
(*pT)->PrintValue();
return 0;
}
// LuaCPP.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "LuaCPP.h"
int _tmain(int argc, _TCHAR* argv[])
{
//打开Lua环境
lua_State* L = luaL_newstate();
//导入常用的库
luaopen_base(L);
//往lua中注册类
//注册用于创建类的全局函数
lua_pushcfunction(L,CreateCTest);
//LUA_GLOBALSINDEX["CTest"]=CreateCTest
lua_setglobal(L,"CTest");
//上面的key必须是必须和下面的原表名字一样吗
//创建一个元表名字为CTest的元表
luaL_newmetatable(L,"CTest");
//__gc是lua默认的清理函数
lua_pushstring(L,"__gc");
lua_pushcfunction(L,DestoryCTest);
lua_settable(L,-3);//公共函数调用的实现就在此啊
lua_pushstring(L,"__index");
//注意这一句,其实是将__index设置成元表自己
lua_pushvalue(L,-2);
lua_settable(L,-3);
//放元素中增加函数,这样所有基于该元素的Table就有Add方法了
lua_pushstring(L,"Add");
lua_pushcfunction(L,CallAdd);
lua_settable(L,-3);
lua_pushstring(L,"Print");
lua_pushcfunction(L,CallPrint);
lua_settable(L,-3);
lua_pop(L,1);
//加载lua文件
luaL_dofile(L,"LuaUseClass.lua");
//查找lua文件中的add函数并入栈
lua_getglobal(L,"add");
//参数1
lua_pushnumber(L,7);
//参数2
lua_pushnumber(L,6);
//调用函数
lua_pcall(L,2,1,0);
//取栈顶的值,此时不知道栈里还有什么值,用1作为索引取回的居然是0,表示栈里不只一个数
//不然1和-1应该是一样的效果
int nresult = lua_tonumber(L,-1);
printf("add result = %d\n",nresult);
//没有思考我直接弹出一个1,至于上面那里的值还没有弹出暂时不追究
lua_pop(L,1);
//退出lua环境
lua_close(L);
return 0;
}
--该文件盒CPP文件在同一个目录,我是直接通过VS工程加入的文件
--add函数
function add(a,b)
--通过CTest(2)调用了C++中的CreateCTest函数并返回了userdata作为表
local test = CTest(2);
--在CreateCTest创建的表是没有函数的,但是他的元表CTest里有函数
--于是test在自己没找到Print,Add等函数时回到CTest元表中查找
--CTest元表在C++中注册的
test:Print();
return test:Add(a,b);
end
--[[
总结:
对C++导出类的方法,看了很多个人的实现代码,都没理解透,
于是自己决定针对一个仔细研究,终于有所收获。对其原理进行了了解。
但是上面可以看出,如果一个类就导入一两个方法还行,如果多导出几个
没个成员函数都去写一个对应的函数太麻烦。网上也就模板的实现方式,
但是自己没达到那个程度一下子能够理解。今天完成这个代码的理解已经
很满足了。
--]]