开发者

How do I set up a metatable to inherit from another metatable while at the same time changing the userdata to another type?

开发者 https://www.devze.com 2023-03-18 19:03 出处:网络
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.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消