LUA注册简单C++类代码走读

   主要是针对网上的一份代码自己的理解注释,下面就直接贴代码了。
//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++导出类的方法,看了很多个人的实现代码,都没理解透,
 于是自己决定针对一个仔细研究,终于有所收获。对其原理进行了了解。
 但是上面可以看出,如果一个类就导入一两个方法还行,如果多导出几个
 没个成员函数都去写一个对应的函数太麻烦。网上也就模板的实现方式,
 但是自己没达到那个程度一下子能够理解。今天完成这个代码的理解已经
 很满足了。
--]]



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值