Как настроить метатабель для наследования от другого метатабеля при одновременном изменении пользовательских данных на другой тип?
Это то, что я хочу сделать в 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
добавляется при необходимости.