在 C++ 和 Lua 之间来回发送变量指针? [英] Sending variable pointers back and forth between C++ and Lua?

查看:24
本文介绍了在 C++ 和 Lua 之间来回发送变量指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在 C++ 和 Lua 之间来回传输变量地址的方法.例如,将对象从 C++ 传输到 Lua 并进行一些处理,然后将其传输回 C++.

I am looking for a way to transfer the variable addresses back and forth between C++ and Lua. For instance, transferring an object from C++ to Lua and do some processing, then transfer it back to C++.

但是,问题是如何从 Lua 执行 C++ 函数或方法?或者是否需要解决方法?

However, the thing is how can you execute a C++ functions or methods from Lua? Or is a workaround required?

如果可能,您能否包含一个代码片段来向我展示它是如何完成的?

If possible, could you include a code snippet to show me how it is done?

我知道我还没有完全理解整个画面,所以如果有什么不对的地方,请纠正我.

I am aware that I do not fully understand the whole picture yet, so if something is amiss, please correct me.

推荐答案

我花了很多时间才让 Lua 与 C++ 类一起工作.Lua 比 C++ 更像是一种 C 风格的 API,但有很多方法可以将它与 C++ 结合使用.

It took me a lot of fiddling around to get Lua to work well with C++ classes. Lua is much more of a C style API than C++ but there are plenty of ways to use it with C++.

在 Lua C API 中,指针由 userdata(或 light userdata)表示没有元表,也没有被垃圾收集).Userdata 可以与元表相关联,元表的作用有点像 Lua 中的类.作为元表一部分的 C 函数包装了 C++ 类的方法,并在 Lua 中充当类的方法.

In the Lua C API a pointer is represented by userdata (or light userdata which have no metatables and are not garbage collected). Userdata can be associated with a metatable which will act a bit like a class in Lua. The C functions that are a part of that metatable wrap the c++ class's methods and act as the class's methods in Lua.

考虑一个具有私有成员名称(c 字符串)和年龄(int)的基本人员类.名称由构造函数设置,不能更改.通过 getter 和 setter 暴露年龄:

Consider a basic person class with private members name (a c string) and age (an int). Name is set by the constructor and can not change. Age is exposed with a getter and setter:

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
",name, age);
    }
    int getAge() {
        return this->age;
    }
    void setAge(int a) {
        this->age=a;
    }
};

为了首先将其暴露给 Lua,我将为所有符合 lua_CFunction 原型的方法编写包装函数,该原型将 lua 状态作为参数并返回一个 int 表示它推送到堆栈的值的数量(通常是一或零).

To expose this to Lua first I will write wrapper functions for all of the methods that conform to the lua_CFunction prototype which takes the lua state as an argument and returns an int for the number of values it pushed on to the stack (usually one or zero).

这些函数中最棘手的是构造函数,它将返回一个像对象一样的 Lua 表.为此,lua_newuserdata 用于创建一个指向对象指针的指针.我假设我们要创建一个元表Person".在包含这些 c 函数的 Lua init 期间.此元表必须与构造函数中的用户数据相关联.

The trickiest of these functions is the constructor which will return a Lua table which acts like an object. To do this lua_newuserdata is used to create a pointer to the pointer to the object. I will assume that we are going to create a meta table "Person" during the Lua init which contain these c functions. This meta table must be associated with the userdata in the constructor.

// 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); 的返回值.

When the other methods are created, you just have to remember that the first argument will always be the pointer to the pointer we created with newPerson. To get the C++ object from that we just de-reference the return from 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;
}

最后在 Lua 的初始化过程中使用 luaL_register 建立了 Person 元表.

Finally the Person meta table is set up using luaL_register during the initializing of 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 中实现 OO.本文涵盖替代方案:http://loadcode.blogspot.com/2007/02/wrapping-c-classes-in-lua.html

There are other ways to implement OO in Lua. This article covers alternatives: http://loadcode.blogspot.com/2007/02/wrapping-c-classes-in-lua.html

这篇关于在 C++ 和 Lua 之间来回发送变量指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆