Отправлять переменные указатели туда и обратно между C++ и Lua?

Я ищу способ передачи адресов переменных назад и вперед между C++ и Lua. Например, перенести объект из C++ в Lua и выполнить некоторую обработку, а затем перенести его обратно в C++.

Однако дело в том, как вы можете выполнять функции или методы C++ из Lua? Или требуется обходной путь?

Если возможно, не могли бы вы включить фрагмент кода, чтобы показать мне, как это делается?

Я осознаю, что еще не до конца понимаю всю картину, поэтому, если что-то не так, пожалуйста, поправьте меня.

3 ответа

Решение

Мне потребовалось много усилий, чтобы заставить Lua хорошо работать с классами C++. Lua - это гораздо больше API в стиле C, чем в C++, но существует множество способов использовать его в C++.

В Lua C API указатель представлен пользовательскими данными (или легкими пользовательскими данными, которые не имеют метатаблицы и не являются сборщиком мусора). Пользовательские данные могут быть связаны с метатаблицей, которая будет немного похожа на класс в Lua. Функции C, являющиеся частью этого метатабеля, обертывают методы класса C++ и действуют как методы класса в Lua.

Рассмотрим базовый класс person с закрытыми именами членов (строка ac) и возрастом (int). Имя задается конструктором и не может быть изменено. Возраст выставляется геттером и сеттером:

class person
{
  private:  
    const char* name;
    int age;
  public:
    person(const char* n) {
        name = strdup(n);
    }
    ~person() {
        free((void*)name);
    }
    void print() {
        printf("%s is %i\n",name, age);
    }
    int getAge() {
        return this->age;
    }
    void setAge(int a) {
        this->age=a;
    }
};

Чтобы сначала представить это Lua, я напишу функции-оболочки для всех методов, которые соответствуют прототипу lua_CFunction, который принимает состояние lua в качестве аргумента и возвращает int для числа значений, которые он помещает в стек (обычно один или ноль).).

Самая хитрая из этих функций - конструктор, который будет возвращать таблицу Lua, которая действует как объект. Для этого lua_newuserdata используется для создания указателя на указатель на объект. Я предполагаю, что мы собираемся создать мета-таблицу "Person" во время инициализации Lua, которая содержит эти c-функции. Эта мета-таблица должна быть связана с пользовательскими данными в конструкторе.

// wrap the constructor
int L_newPerson(lua_State* L) {
    //pointer to pointer
    person **p = (person **)lua_newuserdata(L, sizeof(person *));
    //pointer to person
    *p = new person(lua_tostring(L, 1)); 
    // associate with Person meta table
    lua_getglobal(L, "Person"); 
    lua_setmetatable(L, -2); 
    return 1;
}

Когда другие методы созданы, вы просто должны помнить, что первый аргумент всегда будет указателем на указатель, который мы создали с помощью newPerson. Чтобы получить объект C++ из этого, мы просто отменяем ссылку на возврат из lua_touserdata(L, 1);.

int L_print(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    (*p)->print();
    return 0;
}

int L_getAge(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    lua_pushnumber(L, (*p)->getAge());
    return 1;
}

int L_setAge(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    (*p)->setAge(lua_tonumber(L, 2));
    return 0;
}

Наконец, мета-таблица Person настраивается с использованием luaL_register во время инициализации Lua.

// our methods...
static const luaL_Reg p_methods[] = {
    {"new", L_newPerson},{"print", L_print},
    {"getAge", L_getAge},{"setAge", L_setAge}, 
    {NULL, NULL}
};

lua_State* initLuaWithPerson() {
    lua_State* L=lua_open();
    luaL_openlibs(L);
    luaL_register(L, "Person", p_methods);  
    lua_pushvalue(L,-1);
    lua_setfield(L, -2, "__index"); 
    return L;
}

и проверить это...

const char* Lua_script = 
    "p1=Person.new('Angie'); p1:setAge(25);"
    "p2=Person.new('Steve'); p2:setAge(32);"
    "p1:print(); p2:print();";

int main() {
    lua_State* L=initLuaWithPerson();
    luaL_loadstring(L, Lua_script);
    lua_pcall(L, 0, 0, 0);
    return 0;
}

Есть и другие способы реализации ОО в Lua. В этой статье рассматриваются альтернативы: http://loadcode.blogspot.com/2007/02/wrapping-c-classes-in-lua.html

Смотрите статью в вики пользователя Lua о привязке кода к Lua. Существует несколько методов создания полезного объекта C++ со стороны Lua, которые варьируются по сложности: от простого удержания Lua непрозрачного указателя, который он не может напрямую использовать, до полного переноса, раскрывающего все методы C++ и, возможно, даже позволяющего объект должен быть расширен методами, написанными на Lua.

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

Для объектно-ориентированной системы ручная работа - это гораздо больше, поэтому один из инструментов привязки, перечисленных на этой странице, значительно облегчит вашу жизнь.

Я не уверен, что это то, что вы ищете, но вы пробовали luabind?

Может быть, этот вопрос также поможет.

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