如何设置metatable从另一个metatable继承,同时将userdata更改为另一种类型?

这是我想用Lua C API在C++中实现的内容。

我正在尝试找出一种让userdata从基本userdata对象派生的好方法。

我想要能够这样做:

local item = me:GetCurrentItem()
print(item:GetPos())

而不是这样:

local item = me:GetCurrentItem()
print(item:GetBaseObject():GetPos())

在这些示例中,me:GetCurrentItem()返回带有某些函数的userdata,但它缺少item:GetBaseObject()返回的基本函数。

我正在以学习为目的在Crysis Wars SDK中绑定Lua。SDK为基本实体提供了一个接口,它是一个结构。 IItem结构(me:GetCurrentItem())相同。 由于这些是结构,我无法将它们转换为基本结构或调用其基本函数。我必须使用IEntity *GetEntity()函数。

我尝试了在__index中更改self指针,但这会导致本地变量"item"变为"entity",这有点显而易见,但我希望在调用GetPos函数后恢复,这在某种程度上似乎不合逻辑。

有没有人对这个问题有一个好的解决方案?

原文链接 https://stackoverflow.com/questions/6605815

点赞
stackoverflow用户312586
stackoverflow用户312586

明显的解决方案是定义一个 item:GetPos() 函数来进行跳转。

function Item:GetPos()
  return self:GetBaseObject():GetPos()
end

这里的 Item 是项的元表。

这比在元表上进行更改更有效,也更少出问题。

EDIT: 我也可以帮你减少冗余。

您可以实现以下两个函数:

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

然后像这样使用:

delegate(Item, 'GetPos', 'GetBaseObject')

那一行就会和上面定义的 Item:GetPos 相同。

如果您需要重复执行此操作,可以使用以下函数进一步优化:

function delegateMany(klass, methodNames, memberName)
  for _,methodName in ipairs(methodNames) do
    delegateMethod(klass, methodName, memberName)
  end
end

这应该允许您执行以下操作:

deletageMany(Item, {'GetPost', 'SetPos', 'GetColor', 'SetColor'}, 'GetBaseObject')

我没有测试过这些函数,所以要小心错误。它们应该适用于“获取属性”(例如self:GetSomething())以及简单访问(例如self.something)。该代码假定您始终使用:来调用委派的方法,因此只要需要,就会添加self。

2011-07-07 07:39:29