This article is the last tutorial on C + + and Lua interaction, after which we will combine cocos2d-x to introduce LUA bindings. This article mainly describes how to bind a simple C + + class into Lua and provide LUA object-oriented access.
Binding C + + classes
Defining C + + classes
First, we define a student class, which has the name (string type) and age (integer), and provides some getter and setter, Finally, a print method is provided. Here are the definitions and implementations of the Student class: Student.h and Student.cpp
Writing binding Code
First, let's write a way to create a student object in Lua:
Copy Code code as follows:
Student **s = (student**) lua_newuserdata (L, sizeof (student*)); LUA would manage student** pointer
*s = new Student; We've allocated memory here, and we'll show you how to get LUA to release this memory at GC.
Next is the definition of the Getname,setname,setage,getage and print methods:
Copy Code code as follows:
int L_setname (lua_state* l)
{
Student **s = (student**) lua_touserdata (L, 1);
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
Lual_checktype (L,-1, lua_tstring);
std::string name = lua_tostring (L,-1);
(*s)->setname (name);
return 0;
}
int L_setage (lua_state* l)
{
Student **s = (student**) lua_touserdata (l,1);
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
Lual_checktype (L,-1, Lua_tnumber);
int age = Lua_tonumber (L,-1);
(*s)->setage (age);
return 0;
}
int L_getname (lua_state* l)
{
Student **s = (student**) lua_touserdata (l,1);
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
Lua_settop (L, 0);
Lua_pushstring (L, (*s)->getname (). C_STR ());
return 1;
}
int L_getage (lua_state* l)
{
Student **s = (student**) lua_touserdata (l,1);
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
Lua_settop (L, 0);
Lua_pushnumber (L, (*s)->getage ());
return 1;
}
int L_print (lua_state* l)
{
Student **s = (student**) lua_touserdata (l,1);
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
(*s)->print ();
return 0;
}
From here we can see that UserData serves as a bridge between C + + and LUA, and we must remember to check that the data type is legitimate when we take data out of the LUA stack.
Registering the C API into LUA
Finally, we need to register the functions just written into the LUA virtual machine.
Copy Code code as follows:
static const struct LUAL_REG stuentlib_f [] = {
{"Create", newstudent},
{"SetName", L_setname},
{"Setage", L_setage},
{"Print", L_print},
{"GetName", L_getname},
{"Getage", L_getage},
{NULL, NULL}
};
int luaopen_student (lua_state *l) {
Lual_newlib (L, Stuentlib_f);
return 1;
}
Now, we add the Luaopen_student function to the previous registration function:
Copy Code code as follows:
static const Lual_reg lualibs[] =
{
{"Base", luaopen_base},
{"Io", luaopen_io},
{"CC", luaopen_student},
{NULL, NULL}
};
Const Lual_reg *lib = lualibs;
for (; Lib->func!= NULL; lib++)
{
Note that if you are not using requiref here, you will need to manually call require "module name" in Lua.
Lual_requiref (L, Lib->name, Lib->func, 1);
Lua_settop (L, 0);
}
Lua access to C + + classes
Now, we operate this student class in Lua. Note that each of the functions we bind requires a student object as an argument, which is a bit inconvenient to use.
Copy Code code as follows:
Local s = cc.create ()
Cc.setname (S, "Zilongshanren")
Print (Cc.getname (s))
Cc.setage (s,20)
Print (Cc.getage (s))
Cc.print (s)
Finally, the result of the output is:
Copy Code code as follows:
Zilongshanren
20
My name Is:zilongshanren, and I age is 20
Provides the Lua object-oriented operations API
Now we can create objects for C + + classes in Lua, but we'd better hope to be able to access them in the object-oriented way in Lua.
Copy Code code as follows:
Local s = cc.create ()
S:setname ("Zilongshanren")
S:setage (20)
S:print ()
And we know that S:setname (XX) is equivalent to S.setname (S,XX), at which point we only need to give s a metatable, and to this metatable set a key for "__index", Value equals its own metatable. Finally, you just need to add some of the previous student class methods to this metatable.
MetaTable
We can create this metatable in registry, and then give it a name as an index, and note that in order to avoid name clashes, the name must be unique.
Copy Code code as follows:
Create the metatable with the name Tname and place it on the top of the current stack and associate it with an item that is tname with a key of registry
int lual_newmetatable (lua_state *l, const char *tname);
Get the name of Tname from the current top of the stack metatable
void Lual_getmetatable (lua_state *l, const char *tname);
Remove the UserData from the current stack index and check to see if this userdata contains the name Tname metatable
void *lual_checkudata (lua_state *l, int index,const char *tname);
Next, we will use these 3 C APIs to correlate a metatable for our student userdata.
Modify binding Code
First, we need to create a new metatable and set the Setname/getname/getage/setage/print function in. Here is a list of new functions, which we'll set up in metatable in a moment.
Copy Code code as follows:
static const struct LUAL_REG studentlib_m [] = {
{"SetName", L_setname},
{"Setage", L_setage},
{"Print", L_print},
{"GetName", L_getname},
{"Getage", L_getage},
{NULL, NULL}
};
Next, we create a metatable and set metatable.__index = matatable. Note that the Cc.student meta table is stored in the registry.
Copy Code code as follows:
int luaopen_student (lua_state *l) {
Lual_newmetatable (L, CC). Student ");
Lua_pushvalue (L,-1);
Lua_setfield (L,-2, "__index");
Lual_setfuncs (L, studentlib_m, 0);
Lual_newlib (L, Stuentlib_f);
return 1;
}
Finally, we remember to associate this meta table with the UserData when creating student, as follows:
Copy Code code as follows:
int newstudent (lua_state * L)
{
Student **s = (student**) lua_newuserdata (L, sizeof (student*)); LUA would manage student** pointer
*s = new Student;
Lual_getmetatable (L, CC). Student ");
Lua_setmetatable (L,-2);
return 1;
}
In addition, when we remove the student object from the LUA stack, we use the following function
Copy Code code as follows:
Student **s = (student**) lual_checkudata (l,1, "CC". Student ");
This lual_checkudata can also detect whether or not it contains CC, in addition to converting elements from a stack of index 1 to UserData. Student the meta table so that the code is more robust. For example, our previous SetName function can be implemented as:
Copy Code code as follows:
int L_setname (lua_state * l)
{
Student **s = (student**) lual_checkudata (l,1, "CC". Student ");
Lual_argcheck (L, S!= NULL, 1, "Invalid user data");
Lual_checktype (L,-1, lua_tstring);
std::string name = lua_tostring (L,-1);
(*s)->setname (name);
}
Here is the complete new binding code for the Student class.
Lua access to C + + classes
Now we can access the C + + object using the object-oriented approach in Lua.
Copy Code code as follows:
Local s = cc.create ()
S:setname ("Zilongshanren")
Print (S:getname ())
S:setage (20)
Print (S:getage ())
S:print ()
The result of this output is:
Copy Code code as follows:
Zilongshanren
20
My name Is:zilongshanren, and I age is 20
Managing C + + memory
When the Lua object is GC, a __gc method is invoked. Therefore, we need to add a __gc method to the bound C + + class.
The first is the implementation of the C + + end:
Then, add the registration function:
Copy Code code as follows:
static const struct LUAL_REG studentlib_m [] = {
{"__tostring", student2string},
{"SetName", L_setname},
{"Setage", L_setage},
{"Print", L_print},
{"GetName", L_getname},
{"Getage", L_getage},
{"__gc", auto_gc},
{NULL, NULL}
};
Finally, we add the output to the Stendent constructor and destructor:
Copy Code code as follows:
Student::student ()
: Name ("Default")
{
cout<< "Student contructor called" <<endl;
}
Student::~student ()
{
cout<< "Student destructor called" <<endl;
}
Next is the LUA code:
Copy Code code as follows:
Local s = cc.create ()
S:setname ("Zilongshanren")
S:setage (20)
S:print ()
--When an object is set to nil, the object created by Cc.create before the other corresponding engine is returned, and when Lua returns to the C program, it invokes the GC
s = Nil
--If you want to manually GC in Lua, you can call the following functions
--collectgarbage
Finally, the results of the program output are as follows:
Copy Code code as follows:
Student Contructor called
My name Is:zilongshanren, and I age is 20
Student destructor called
Summarize
This article mainly describes how to use UserData to bind C + + custom types to Lua, and by introducing metatable, we can access the derived classes in Lua with more concise object-oriented notation. In the next article, we will introduce the tolua++ and its basic usage in cococs2d-x. PS: Attach the source code of this article, pay attention to the Luacocos2d-x project inside.