Как настроить метатабель для наследования от другого метатабеля при одновременном изменении пользовательских данных на другой тип?

Это то, что я хочу сделать в C++, используя Lua C API.

Я пытаюсь найти хороший способ получения пользовательских данных из базового объекта пользовательских данных.

Я хочу быть в состоянии сделать это:

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

вместо:

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

В этих примерах me:GetCurrentItem() возвращает пользовательские данные с некоторыми функциями, но в нем отсутствуют базовые функции, которые возвращает элемент:GetBaseObject().

Я связываю Луа в Crysis Wars SDK для учебных целей. SDK предоставляет интерфейс к базовому объекту, который является структурой. Структура IItem (me:GetCurrentItem()) такая же. Поскольку это структуры, я не могу привести их к базовой структуре или вызвать ее базовые функции. Я должен использовать функцию IEntity *GetEntity().

Я попытался изменить указатель self в __index, но он заставляет локальную переменную "item" становиться "сущностью", что довольно очевидно, но я хочу, чтобы она вернулась назад после вызова функции GetPos, что как-то нелогично.

У кого-нибудь есть хорошее решение этой проблемы?

1 ответ

Решение

Очевидным решением будет определение элемента: функция GetPos(), которая выполняет перенаправление.

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

Где пункт - метатабельный элемент.

Это так же эффективно, как и внесение изменений в метатаблицу, и менее проблематично.

РЕДАКТИРОВАТЬ: Я могу помочь вам немного с повторяемостью тоже.

Вы можете реализовать следующие две функции:

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 3-строчное определение выше.

Если вам нужно многократно повторять это, вы можете оптимизировать его с помощью этой другой функции:

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 добавляется при необходимости.

Другие вопросы по тегам