使用LUA userdata手动绑定C++对象

人老了容易忘记以前做过事情,第一次写自己的博客! 


本文使用的LUA5.1版本


lua.hpp

// lua.hpp
// Lua header files for C++
// <<extern "C">> not supplied automatically because Lua also compiles as C++

#ifdef __cplusplus  
extern "C" {
#endif
	#include "lua.h"
	#include "lualib.h"
	#include "lauxlib.h"
#ifdef __cplusplus
}
#endif

Student.h

#ifndef __STUDENT_H_
#define __STUDENT_H_


#include "lua.hpp"

class Student
{
public:
	Student();
	void SetAge(int nAge);
	int GetAge();

	int m_nAge;
};


#ifdef __cplusplus
extern "C" {
#endif
	int luaopen_student(lua_State *L);
#ifdef __cplusplus
}
#endif




#endif


Student.cpp

#include "Student.h"

Student::Student()
{
	m_nAge = 0;
}

void Student::SetAge(int nAge)
{
	this->m_nAge = nAge;
}


int Student::GetAge()
{
	return this->m_nAge;
}

static int Create(lua_State *L) {
	Student **s =  (Student**)lua_newuserdata(L, sizeof(Student*));
	*s = new Student;

	// 将userdata自定义数据与元表Meta_Student相关联
	luaL_getmetatable(L, "Meta_Student");
	lua_setmetatable(L, -2);

	return 1;
}


static int SetAge(lua_State *L) {
	Student **s = (Student**)luaL_checkudata(L, 1, "Meta_Student");
	luaL_argcheck(L, s != NULL, 1, "invalid user data");

	int nAge = (int)lua_tonumber(L, -1);
	(*s)->SetAge(nAge);

	return 0;
}

static int GetAge(lua_State *L) {
	Student **s = (Student**)luaL_checkudata(L, 1, "Meta_Student");
	luaL_argcheck(L, s != NULL, 1, "invalid user data");

	lua_pushnumber( L, (lua_Number)((*s)->GetAge()) );

	return 1;
}

static int AutoDel(lua_State *L) {
	Student **s = (Student**)luaL_checkudata(L, 1, "Meta_Student");
	luaL_argcheck(L, s != NULL, 1, "invalid user data");

	delete (*s);

	return 0;
}


int luaopen_student(lua_State *L) 
{
	luaL_Reg reg[] = 
	{
		{"Create", Create },
		{NULL,NULL},
	};

	// 创建名字为“Meta_Student”元表
	luaL_newmetatable(L, "Meta_Student");

	//修改元表“Meta_Student”查找索引,把它指向“Meta_Student”自身
	lua_pushvalue(L, -1);
	lua_setfield(L, -2, "__index");

	// GetAge方法
	lua_pushcfunction(L, GetAge);
	lua_setfield(L, -2, "GetAge");

	// SetAge方法
	lua_pushcfunction(L, SetAge);
	lua_setfield(L, -2, "SetAge");

	// 自动删除,如果表里有__gc,Lua的垃圾回收机制会调用它。
	lua_pushcfunction(L, AutoDel);
	lua_setfield(L,-2,"__gc");

	// 注册reg中的方法到Lua中(“Student”相当于类名),reg中的方法相当于Student成员函数
	luaL_register(L, "Student", reg);

	return 1;
}

main.lua

print(Student)  
--[[ 
    1.打印Student地址
    2.打印nil --> luaL_register(L, "Student", reg); 这段代码没有执行成功
]]

local p = Student.Create()
--[[
调用C++代码:
static int Create(lua_State *L) {
    Student **s =  (Student**)lua_newuserdata(L, sizeof(Student*));
    *s = new Student;

    // 将userdata自定义数据与元表Meta_Student相关联
    luaL_getmetatable(L, "Meta_Student");
    lua_setmetatable(L, -2);

    return 1;
}

@retrun p-> Student*
]]

p:SetAge(1200)     -- 调用方法1
p.SetAge(p, 1000)   -- 调用方法2
--[[
p:SetAge() p(userdata)没有注册SetAge方法, 就会寻找与p(userdata)相关联的元表Meta_Student有SetAge方法!并调用!

调用C++代码:
static int SetAge(lua_State *L) {
    Student **s = (Student**)luaL_checkudata(L, 1, "Meta_Student");
    luaL_argcheck(L, s != NULL, 1, "invalid user data");

    int nAge = (int)lua_tonumber(L, -1);
    (*s)->SetAge(nAge);

    return 0;
}

]]


print(p:GetAge())
--[[
调用C++代码:
static int GetAge(lua_State *L) {
    Student **s = (Student**)luaL_checkudata(L, 1, "Meta_Student");
    luaL_argcheck(L, s != NULL, 1, "invalid user data");

    lua_pushnumber( L, (lua_Number)((*s)->GetAge()) );

    return 1;
}
]]


main.cpp

// MyCma.cpp : 定义控制台应用程序的入口点。
//

//#include <SDKDDKVer.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <string>
#include "lua.hpp"
#include "Student.h"


int _tmain(int argc, _TCHAR* argv[])
{

	lua_State* L = luaL_newstate();
	luaL_openlibs(L);
	luaopen_student(L);
	luaL_dofile(L, "main.lua");
	lua_close(L);

	system("pause");

	return 0;
}

特别注意: 使用lua userdata创建 C++  Student对象生命周期的问题!我使用lua gc删除C++  Student对象!

关于生命周期可以参考cocos2d-x自动释放池,也可以考虑一下云风大神博文!


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Lua中,Userdata是一种特殊类型的变量,可以存储C/C++编写的数据结构。由于Userdata是由C/C++编写的,因此不能直接在Lua中进行遍历,但是可以通过添加元方法来实现遍历操作。 在C/C++中,可以通过向Userdata添加元表(Metatable)来定义遍历操作。首先,需要在C/C++中编写一个函数,用于获取Userdata中的数据结构。然后,将该函数与__ipairs元方法关联,以实现Userdata的遍历。 以下是一个示例的C代码片段,在该代码中定义了一个用于遍历Userdata的元方法: ```c typedef struct { int data[10]; int length; } UserData; int get_data(lua_State *L) { UserData *ud = (UserData *)lua_touserdata(L, 1); int index = luaL_checkinteger(L, 2); if (index >= 1 && index <= ud->length) { lua_pushinteger(L, ud->data[index - 1]); return 1; } return 0; } int userdata_pairs(lua_State *L) { lua_pushcfunction(L, get_data); lua_pushvalue(L, 1); lua_pushinteger(L, 0); return 3; } int luaopen_userdata(lua_State *L) { // 创建userdata类型 luaL_newmetatable(L, "userdata"); // 设置__pairs元方法 lua_pushcfunction(L, userdata_pairs); lua_setfield(L, -2, "__pairs"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); return 1; } ``` 在Lua中,使用上述定义的Userdata类型和元方法进行遍历操作的示例代码如下: ```lua local userdata = require("userdata") local ud = userdata.new() ud:push(1) ud:push(2) ud:push(3) ud:push(4) ud:push(5) for i, v in ipairs(ud) do print(i, v) end ``` 输出结果: ``` 1 1 2 2 3 3 4 4 5 5 ``` 上述示例中,通过添加__pairs元方法,用户可以使用ipairs遍历Userdata中的元素。在每次迭代时,调用get_data函数获取userdata中指定位置的元素。 需要注意的是,Userdata的具体实现和元方法的定义根据实际需求可能会有所不同,上述示例仅供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值