Переопределение метода c ++ в lua и обратный вызов в c ++ - PullRequest
7 голосов
/ 21 января 2011

Однажды я подумал, что могу переопределить метод класса в lua, чтобы при вызове этой функции в C ++ он делал то, что переопределил в lua.Я имею в виду, вот так:

C ++ class


class Person {
public:
  Person(); // ctr
  virtual void shout(); // Meant to be overriden
};

Предположим, что у меня есть этот класс, связанный с lua, так что в lua я могу использовать объект:


--Lua code
p = Person:new()
p:shout()

Я пытаюсь добиться чего-то подобного:

Lua file


--luafile.lua
p = Person:new() --instantiate

--override shout()
p.shout = function(self) print("OVERRIDEN!") end

C ++ code


int main() {
  lua_State* l = lua_open();
  luaL_loadlibs(l);
  bind_person_class(l);

  luaL_dofile("luafile.lua");
  Person* p = (Person*) get_userdata_in_global(l, "p"); // get the created person in lua
  p->shout(); // expecting "OVERRIDEN" to be printed on screen

  lua_close(l);
  return 0;
}

В приведенном выше коде вы можете видеть, что я пытаюсь переопределить метод Person в lua и ожидаю, что переопределенный метод будет вызываться из c ++.Однако, когда я пытаюсь это сделать, переопределенный метод не выполняется.Я пытаюсь добиться того, чтобы переопределенный метод выполнялся в C ++.Как вам этого добиться?

===================

Я подумал, как этого добиться, но я 'Я не уверен, хорошо ли это.Моя идея заключается в том, что экспортируемый класс должен иметь строку, представляющую имя глобальной переменной в lua, которое используется для хранения экземпляра этого класса.Например:


class Person {
public:
  Person();
  string luaVarName; // lua's global variable to hold this class
  virtual void shout() { 
    luaL_dostring(luaVarName + ":shoutScript()"); // now shout will call shoutScript() in lua
  }
};

Итак, в lua объект отвечает за реализацию shoutScript () и присваивает объекту глобальную переменную:


--LUA
p = Person:new()
p.shoutScript = function(self) print("OVERRIDEN") end
p.luaVarName = "p"

С помощью приведенных выше кодов я могу добиться того, чтоЯ хочу (пока не проверял).Но, Есть ли другой, правильный способ достичь того, чего я хочу?

Ответы [ 2 ]

4 голосов
/ 21 января 2011

То, что мы сделали в lqt , автоматическом связывании Qt с Lua, заключается в том, что для каждого связываемого нами класса, имеющего виртуальные методы, мы создаем прокси-класс «shell», который регистрируется в состояние Луа.

Итак, для вашего (упрощенного) класса:

class Person {
public:
  virtual void shout(); // Meant to be overriden
};

Мы генерируем следующий класс:

class lqt_shell_Person : public Person {
  lua_State *L;
public:
  lqt_shell_Person(lua_State *L); // registers itself into the Lua state
  virtual void shout();
};

Мы представляем эти объекты в Lua, используя userdata. У каждого своя собственная таблица окружения, на которую мы указываем метаметоды __newindex и __index (функция __index ищет в среде, а затем в таблице классов). Используя это, пользователь может хранить настраиваемые поля на объектах. Он также может реализовывать виртуальные функции, например:

p = Person.new()
function p:shout() print("Hello world!") end

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

Надеюсь, вы найдете это полезным.

2 голосов
/ 21 января 2011

Lua «идеологически» отличается от C ++. Lua - это язык на основе прототипа OO . C ++ - это ОО-язык на основе классов. Lua может изменять интерфейс объектов во время выполнения, C ++ не может изменять тип объектов после создания объекта.

Так что, что бы вы ни делали с интерфейсом объектов lua, изменения не отражаются обратно в программе на C ++, а остаются в lua.

...