主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍)
部分内容查阅自:《Lua 5.3 参考手册》中文版 译者 云风 制作 Kavcc
vs2013+lua-5.3.3
1.C++中学生Student类
①头文件Student.h
1 #pragma once
2
3 #include <iostream>
4 #include <string>
5
6 class Student
7 {
8 public:
9 //构造/析构函数
10 Student();
11 ~Student();
12
13 //get/set函数
14 std::string get_name();
15 void set_name(std::string name);
16 unsigned get_age();
17 void set_age(unsigned age);
18
19 //打印函数
20 void print();
21
22 private:
23 std::string _name;
24 unsigned _age;
25 };
②实现文件student.cpp
1 #include "Student.h"
2
3 Student::Student()
4 :_name("Empty"),
5 _age(0)
6 {
7 std::cout << "Student Constructor" << std::endl;
8 }
9
10 Student::~Student()
11 {
12 std::cout << "Student Destructor" << std::endl;
13 }
14
15 std::string Student::get_name()
16 {
17 return _name;
18 }
19
20 void Student::set_name(std::string name)
21 {
22 _name = name;
23 }
24
25 unsigned Student::get_age()
26 {
27 return _age;
28 }
29
30 void Student::set_age(unsigned age)
31 {
32 _age = age;
33 }
34
35 void Student::print()
36 {
37 std::cout << "name :" << _name << " age : " << _age << std::endl;
38 }
2.C++中定义注册全局函数到Lua中
①头文件StudentRegFuncs.h
1 #pragma once
2
3 #include "Student.h"
4 #include "lua.hpp"
5
6 //------定义相关的全局函数------
7 //创建对象
8 int lua_create_new_student(lua_State* L);
9
10 //get/set函数
11 int lua_get_name(lua_State* L);
12 int lua_set_name(lua_State* L);
13 int lua_get_age(lua_State* L);
14 int lua_set_age(lua_State* L);
15
16 //打印函数
17 int lua_print(lua_State* L);
18
19 //------注册全局函数供Lua使用------
20 static const luaL_Reg lua_reg_student_funcs[] = {
21 { "create", lua_create_new_student },
22 { "get_name", lua_get_name },
23 { "set_name", lua_set_name },
24 { "get_age", lua_get_age },
25 { "set_age", lua_set_age },
26 { "print", lua_print },
27 { NULL, NULL },
28 };
29
30 int luaopen_student_libs(lua_State* L);
②实现文件StudentRegFuncs.cpp
1 #include "StudentRegFuncs.h"
2
3 int lua_create_new_student(lua_State* L)
4 {
5 //创建一个对象指针放到stack里,返回给Lua中使用
6 Student** s = (Student**)lua_newuserdata(L, sizeof(Student*));
7 *s = new Student();
8 return 1;
9 }
10
11 int lua_get_name(lua_State* L)
12 {
13 //得到第一个传入的对象参数(在stack最底部)
14 Student** s = (Student**)lua_touserdata(L, 1);
15 luaL_argcheck(L, s != NULL, 1, "invalid user data");
16
17 //清空stack
18 lua_settop(L, 0);
19
20 //将数据放入stack中,供Lua使用
21 lua_pushstring(L, (*s)->get_name().c_str());
22
23 return 1;
24 }
25
26 int lua_set_name(lua_State* L)
27 {
28 //得到第一个传入的对象参数
29 Student** s = (Student**)lua_touserdata(L, 1);
30 luaL_argcheck(L, s != NULL, 1, "invalid user data");
31
32 luaL_checktype(L, -1, LUA_TSTRING);
33
34 std::string name = lua_tostring(L, -1);
35 (*s)->set_name(name);
36
37 return 0;
38 }
39
40 int lua_get_age(lua_State* L)
41 {
42 Student** s = (Student**)lua_touserdata(L, 1);
43 luaL_argcheck(L, s != NULL, 1, "invalid user data");
44
45 lua_pushinteger(L, (*s)->get_age());
46
47 return 1;
48 }
49
50 int lua_set_age(lua_State* L)
51 {
52 Student** s = (Student**)lua_touserdata(L, 1);
53 luaL_argcheck(L, s != NULL, 1, "invalid user data");
54
55 luaL_checktype(L, -1, LUA_TNUMBER);
56
57 (*s)->set_age((unsigned)lua_tointeger(L, -1));
58
59 return 0;
60 }
61
62 int lua_print(lua_State* L)
63 {
64 Student** s = (Student**)lua_touserdata(L, 1);
65 luaL_argcheck(L, s != NULL, 1, "invalid user data");
66
67 (*s)->print();
68
69 return 0;
70 }
71
72 int luaopen_student_libs(lua_State* L)
73 {
74 luaL_newlib(L, lua_reg_student_funcs);
75 return 1;
76 }
③ C++和Lua之间的交互是通过lua_newuserdata创建出来的内存块进行交互的
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
这个函数分配一块指定大小的内存块, 把内存块地址作为一个完全用户数据压栈, 并返回这个地址。 宿主程序可以随意使用这块内存。
④注意传入参数的检查宏luaL_argcheck
1 #define luaL_argcheck(L, cond,arg,extramsg)
2 ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
如果cond条件不为true,则抛出一个错误报告调用的 C 函数的第 arg 个参数的问题。
⑤类型检查函数luaL_checktype
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
检查函数的第 arg 个参数的类型是否是 t。
3.将对应的全局函数注册到Lua中
①加入到注册模块列表中去
1 static const luaL_Reg lua_reg_libs[] = {
2 { "base", luaopen_base }, //系统模块
3 { "Student", luaopen_student_libs}, //模块名字Student,注册函数luaopen_student_libs
4 { NULL, NULL }
5 };
②注册到Lua中
1 //注册让lua使用的库
2 const luaL_Reg* lua_reg = lua_reg_libs;
3 for (; lua_reg->func; ++lua_reg){
4 luaL_requiref(L, lua_reg->name, lua_reg->func, 1);
5 lua_pop(L, 1);
6 }
4.在Lua中进行调用(Student为模块名)
1 local student_obj = Student.create()
2 Student.set_name(student_obj,"Jack")
3 Student.print(student_obj)
可以看到,调用的方式需要使用模块名,并且第一个参数为创建的对象,和我们熟悉的面向对象的调用方式不一样。
Lua中面向对象的实现在下一节《Lua和C++交互 学习记录之九:在Lua中以面向对象的方式使用C++注册的类》。
Lua和C++交互系列:
《Lua和C++交互 学习记录之七:C++全局函数注册为Lua模块》