Как настроить метатабель для наследования от другого метатабеля, одновременно изменяя пользовательские данные на другой тип? - PullRequest
1 голос
/ 07 июля 2011

Это то, что я хочу сделать в 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" становиться "entity", что довольно очевидно, но я хочу, чтобы он вернулся обратно после вызова функции GetPos, которая выглядитнелогично как-то.

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

1 Ответ

2 голосов
/ 07 июля 2011

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

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

Где Item - метатабельный элемент.

Это так же эффективно, как и вносить изменения.на метатабельных и менее проблемных.

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

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

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

...