Отправлять переменные указатели туда и обратно между C ++ и Lua? - PullRequest
1 голос
/ 14 августа 2010

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

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

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

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

Ответы [ 3 ]

9 голосов
/ 18 августа 2010

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

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

Рассмотрим базовый класс person с закрытыми именами (строка c) и возрастом (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

4 голосов
/ 14 августа 2010

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

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

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

2 голосов
/ 14 августа 2010

Я не уверен, что это то, что вы ищете, но вы пытались Luabind

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

...