Hello I have the following bit of code which seems to work, but I'm not sure why - I've built a testclass as follows
class testclass {
int ivalue;
public:
int getivalue();
void setivalue(int &v);
};
and then registered the testclass (bits left out for the actual functions but they're pretty basic). It's the registration of the metatables I'm not following. (etivalue and setivalue are c functions that call the class functions of the same name)
static const struct luaL_Reg arraylib_f [] = {
{"new", new_testclass},
{NULL, NULL}
};
static const struct luaL_Reg arraylib_m [] = {
{"set", setivalue},
{"get", geti开发者_StackOverflow中文版value},
{NULL, NULL}
};
int luaopen_testclass (lua_State *L) {
luaL_newmetatable(L, "LuaBook.testclass");
lua_pushvalue(L, -1); /* duplicates the metatable */
lua_setfield(L, -2, "__index");
luaL_register(L, NULL, arraylib_m);
luaL_register(L, "testclass", arraylib_f);
return 1;
}
The bit I don't understand is I'm adding the functions to the __index for the metatable but when I run
a = testclass.new()
a:set(10)
print(a:get())
Then it works as expected. The bit I don't understand is why the set is being called when I think I've loaded it in the __index metatable? Is that what I've done or something else?
tia
int luaopen_testclass (lua_State *L) {
luaL_newmetatable(L, "LuaBook.testclass"); //leaves new metatable on the stack
lua_pushvalue(L, -1); // there are two 'copies' of the metatable on the stack
lua_setfield(L, -2, "__index"); // pop one of those copies and assign it to
// __index field od the 1st metatable
luaL_register(L, NULL, arraylib_m); // register functions in the metatable
luaL_register(L, "testclass", arraylib_f);
return 1;
}
That code is equivalent to the example Lua code:
metatable = {}
metatable.__index = metatable
metatable.set = function() --[[ stuff --]] end
metatable.get = function() --[[ stuff --]] end
I assume that 'new_testclass' C function sets the metatable "LuaBook.testclass" for the returned table.
In your code you dont add functions to the metatable __index field. You assign pointer to metatable to that metatable's field named __index, and you register set and get functions to it.
Now, if you set that metatable to the value returned from 'new_testclass' function (which I assume you do) - lets call that value 'foo', and you call foo:set(10), than Lua:
- checks that there is no such field as 'set' in 'foo'
- sees that 'foo' has a metatable
- looks at that metatable's __index field - sees it's a table
- checks if that table assigned to __index field has a field 'set' and it's value is a function
- calls 'set' method passing 'foo' as self parameter
I hope that this will help you figure out whats going on here.
If I understand your question, you are asking how the set()
get()
get invoked through the __index
metamethod.
The code can be expressed in pure lua:
local o = {}
function o.get(self)
return self.ivalue
end
function o.set(self, val)
self.ivalue = val
end
a = {}
mt = {
__index = function(t, n)
return o[n]
end
}
setmetatable(a, mt)
print(a:get())
a:set(10)
print(a:get())
results:
nil
10
In this example the mt
table is set as the a
table's metatable. The __index
metamethod is invoked for both get
and set
since neither get
or set
currently exist in table a
.
If this example is changed instead to this:
local o = {}
function o.get(self)
return self.ivalue
end
function o.set(self, val)
self.ivalue = val
end
a = {}
function a.get(self)
print('here')
return self.ivalue
end
mt = {
__index = function(t, n)
return o[n]
end
}
setmetatable(a, mt)
print(a:get())
a:set(10)
print(a:get())
results:
here
nil
here
10
In this case the __index
metamethod is NOT invoked for get()
since a get
index already exists in the a
table.
Many interesting constructs can be created using metamethods, once you understand how they work. I suggest reading 13.4.1 - The __index Metamethod in PiL and work through a few more examples. All of the above can also be done from the c api.
精彩评论