How do I set up a metatable to inherit from another metatable while at the same time changing the userdata to another type?
This is something I want to do in C++ using the Lua C API.
I'm trying to figure out a good way to make userdata derive from a base userdata object.
I want to be able to do this:
local item = me:GetCurrentItem()
print(item:GetPos())
instead of:
local item = me:GetCurrentItem()
print(item:GetBaseObject():GetPos())
In these examples, me:GetCurrentItem() returns userdata with some functions, but it lacks the base functions which item:GetBaseObject() returns.
I'm binding Lua in the Crysis Wars SDK for learning purposes. The SDK provides an interface to the base entity which is a struct. The IItem struct (me:GetCurrentItem()) is the same. Since these are structs I 开发者_JAVA百科can't cast them to the base struct or call its base functions. I have to use the IEntity *GetEntity() function.
I've tried chaning the self pointer in __index but it causes the local variable "item" to become "entity" which is kinda obvious, but I want it to revert back after calling the GetPos function, which seems illogical somehow.
Does anyone have a good solution to this issue?
The obvious solution would be defining an item:GetPos() function that does the redirect.
function Item:GetPos()
return self:GetBaseObject():GetPos()
end
Where Item is the item's metatable.
This is as efficient as making changes on the metatable, and less problematic.
EDIT: I can help you a bit with the repetitiveness too.
You can implement the following two functions:
function delegate(klass, methodName, memberName)
klass[methodName] = function(self, ...)
local member = self[memberName]
if type(member) == 'function' then member = self[memberName](self) end
return member[methodName](member, ...)
end
end
And then use it like this:
delegate(Item, 'GetPos', 'GetBaseObject')
That single line whould do the same as the Item:GetPos
3-line definition above.
If you need to repeat this a lot, you can optimize it further with this other function:
function delegateMany(klass, methodNames, memberName)
for _,methodName in ipairs(methodNames) do
delegateMethod(klass, methodName, memberName)
end
end
Which should allow you to do:
deletageMany(Item, {'GetPost', 'SetPos', 'GetColor', 'SetColor'}, 'GetBaseObject')
I haven't tested any of these functions, so beware of bugs. They should work with both "gotten properties" (self:GetSomething()
as well as simple accesses self.something
). The code assumes that you would always use ':' to invoke the delegated methods, so self
is added when needed.
精彩评论