2015-01-12 4 views
5

Я использую lua в качестве языка сценариев для своего 3d-движка. У меня есть «классы» для нескольких объектов, и теперь я хочу использовать свойства вместо геттеров и сеттеров. Так что вместо того, чтобы что-то вроде этогоLua: методы и свойства при экспорте класса из c

local oldState = ui:GetChild("Panel1"):GetVisible() 
ui:GetChild("Panel1"):SetVisible(not oldState) 

Я бы просто

ui.Panel1.visible = not ui.Panel1.visible 

Проблема мой C++ код для создания метатаблицы и инстанс переопределяет метод __index. Здесь, кстати:

  1. Создайте метатаблицу:

    void CLUAScript::RegisterClass(const luaL_Reg funcs[], std::string const& className) 
    { 
        luaL_newmetatable(m_lua_state, std::string("Classes." + className).c_str()); 
        luaL_newlib(m_lua_state, funcs); 
        lua_setglobal(m_lua_state, className.c_str()); 
    } 
    
  2. экземпляр класса (объект Lua имеет только указатель на фактических данных, которые хранятся в C++ код):

    int CLUAScript::NewInstanceClass(void* instance, std::string const& className) 
    { 
        if (!instance) 
        { 
         lua_pushnil(m_lua_state); 
         return 1; 
        } 
    
        luaL_checktype(m_lua_state, 1, LUA_TTABLE); 
    
        lua_newtable(m_lua_state); 
    
        lua_pushvalue(m_lua_state,1);  
        lua_setmetatable(m_lua_state, -2); 
    
        lua_pushvalue(m_lua_state,1); 
        lua_setfield(m_lua_state, 1, "__index"); 
    
        void **s = (void **)lua_newuserdata(m_lua_state, sizeof(void *)); 
    
        *s = instance; 
        luaL_getmetatable(m_lua_state, std::string("Classes." + className).c_str()); 
        lua_setmetatable(m_lua_state, -2); 
        lua_setfield(m_lua_state, -2, "__self"); 
    
        return 1; 
    } 
    

вопрос заключается в том, как я могу иметь оба свойства и методы. Если я просто добавлю __index в CLUAScript::RegisterClass funcs array, он никогда не вызывается. И я не могу себе представить, как удалить его переопределение в CLUAScript::NewInstanceClass.

Если этот код не хватает, вот ссылки на файлы, работающих с Lua: lua helper class, functions for UI, functions for Objects и testing lua script

+0

Чтобы уточнить связь между кодом и Lua кода C++, что 'ui' и что делает' Ui: GetChild ("property_name ")' return? Например, 'ui' пользовательские данные из земли C++ или это какая-то таблица, возвращаемая' NewInstanceClass' с набором '__self = udata_object'? – greatwolf

+0

«ui» - это экземпляр элемента пользовательского интерфейса, например кнопки, панели или всего экрана. Каждый элемент может иметь дочерние элементы, которые можно использовать с помощью метода GetChild (name). Эти дочерние элементы также будут элементами пользовательского интерфейса. Таким образом, это таблица, содержащая указатель на экземпляр C++ как userdata и некоторые методы из metatable, возвращаемые функцией NewInstanceClass. В этом случае «ui» является локальной переменной, которая представляет весь экран (корневой элемент дерева UI). –

+0

Что делать, если вы выполняете функции 'GetChild' и' GetVisible' в lua? Затем вы можете просто сделать 'ui.Panel1' как форму синтаксического сахара, которая переводится в' GetChild (ui, "Panel1") '. – greatwolf

ответ

2

Вопрос заключается в том, как я могу иметь оба свойства и методы ,

Вообще говоря, методы - это просто свойства, которые решаются для функций.

Если я просто добавлю __index к массиву funset RegisterClass, он никогда не вызывается.

Это настоящая проблема, не так ли? Остальная часть вашего сообщения отвлекается от реальной проблемы.

Согласно документам, luaL_newlib creates a new table. Так luaL_newmetatable. Вы создаете две таблицы в RegisterClass, что не имеет смысла. Вам нужно создать только метатет, и это метатет, что вам нужно добавить ваши метаметоды и __newindex.

У вас не будет __index просто укажите таблицу funcs (ярлык для реализации методов класса), а не если вы хотите вручную маршевать данные в свойства экземпляра класса C++ и из них. Это должна быть функция, которая отличает доступ к методу (значение относится к классу) и доступ к свойствам (значение происходит из области экземпляра).


Вот пример того, как ваш доступ к методу/собственности будет работать в Lua.Специфика отличаются использованием API C, но подход был бы тот же:

-- This is the metatable you create in RegisterClass for the C++ class 'Foo' 
Foo = { } 

-- This is pretty close to how your __index metamethod would work in the C++ code, 
-- except you're going to have to write code that resolves which field on the C++ object 
-- corresponds to 'key', if any, and push that onto the stack. 
function Foo.__index(instance,key) 
    local method = rawget(Foo,key) 
    if method then 
     return method 
    end 
    return instance.properties[key] 
end 

-- This is pretty close, too, except that if you want users to be able to add properties to the Lua object 
-- that coexist with the C++ object properties, you'll need to write the value to the right place. 
function Foo.__newindex(instance,key,value) 
    instance.properties[key] = value 
end 

-- this doesn't have to be a method on the metatable 
function Foo:new(state) 
    return setmetatable({ properties = state}, self) 
end 

-- example of a class method 
function Foo:dump() 
    print('dump:', self.x, self.y) 
end 

-- simulation of the userdata, an instance of your C++ class 
cppClassInstance = { 
    x = 10, 
    y = 20, 
} 

obj = Foo:new(cppClassInstance) 
print(obj.x) -- read `x`, which is resolved to cppClassInstance.x 
obj.x = 5150 -- write to 'x', which writes to cppClassInstance.x 
print(obj.x) -- witness our change 
obj:dump() -- call a class method