Lua 中的面向对象编程从 C 语言实现

我想在我的 Lua 解释器中实现面向对象编程。我知道可以从 C 函数返回 Lua 表。而且我希望返回的表格中充满了 C 函数。

player = getClosestPlayer();
player.walkTo();

其中 getClosestPlayer() 和 walkTo() 都是 C 函数。

从 walkTo() 的 C 函数中,如何区分类型?

我希望每个对象都有一个 gid,以便我可以使用它来标识对象 (player.gid),但我如何从 c 函数中访问该 gid?

换句话说,如何在 C 代码中实现相当于 self.gid 的功能?

int l_playerWalkTo(lua_State* functionState){
    int gid = // self.gid?
    // do something with gid
}

我可以使用一个 upvalue 来为表中的每个函数提供上下文,但是否有更优雅的方法来实现呢?

点赞
用户1521241
用户1521241

我有类似的问题,解决的方法是:

1)在C++中创建一个抽象方法的接口类

class LuaInterfaceOOP
{
public:
    LuaInterfaceOOP(){}
    virtual CObject* clone(void) const=0;
    virtual wxString type(void)=0;
    virtual wxString ToString(void)=0;
    wxString GetType()return this->type();
    wxString GetToString() return this->ToString();
    virtual ~CObject(){}
};

2)任何你想要在Lua中使用的类都应该实现这个接口,以保持一致性

class MyClass: public LuaInterfaceOOP
{
 public:
 wxString type() { return "MyClass";}
 wxString ToString();
};

3)当你为这个类写一个包装器的时候,确保

int MyClass_toString(lua_State* L)
{
    MyClass* mc= luaW_check<MyClass>(L, 1);
    const char* str=mc->ToString().c_str();
    lua_pushstring(L, str);

    return 1;
}

int MyClass_type(lua_State* L)
{
    lua_pushstring(L,"MyClass");

    return 1;
}

4)重载Lua提供的type函数,对你来说最重要的部分将是:

case LUA_TUSERDATA:
{
    wxString str1;
    if(lua_getmetatable(L,idx)) // Stk: Userdata Table
    {
        lua_getfield(L,-1,"type");  // Stk: Userdata Table function
        if(!lua_pcall(L,0,1,0))     // Stk: Userdata Table string
        {
            str1<<lua_tostring(L,-1);
            wxReturnStr<<str1;
            lua_pop(L,2);// Stk: Userdata
        }
        else //stk: Userdata table
        {
            lua_pop(L,1);
            wxReturnStr<<"userdata"; //stk: Userdata
        }

    }else wxReturnStr<<"userdata";
    break;
}

编辑1:添加将C++函数包装到Lua的代码

static luaL_Reg MyClass_table[] = {
    { NULL, NULL }
};

static luaL_Reg Myclass_metatable[] = {
    {"type",    Myclass_type},
    {"__tostring",      Myclass_toString},
    { NULL, NULL }
};

最后,

static int luaopen_MyClass(lua_State* L)
{
    luaW_register<MyClass>(L, "MyClass", MyClass_table, MyClass_metatable, MyClass_new);
   return 1;
}

现在在Lua中,你可以使用诸如if(type(aclass)=="MyClass")这样的表达式。

我不确定这些步骤是否是最好的方式,但到目前为止它起作用了。

2016-05-21 03:08:44
用户5624167
用户5624167

感谢 macroland 的回答,我只是想澄清一下他所说的。 这个 Lua 包装器可以用于将 C++ 类实现到 Lua 中: https://bitbucket.org/alexames/luawrapper/overview

使用这个库的一个很好的例子可以在这里找到: https://bitbucket.org/alexames/luawrapperexample/src/

这是代码(直接从示例网站中拿的):

Lua:

alicesaccount = BankAccount.new("Alice", 100)

alicesaccount:deposit(20);
alicesaccount:deposit(30);
alicesaccount:deposit(40);

C++:

BankAccount* BankAccount_new(lua_State *L)
{
    const char* owner = luaL_checkstring(L, 1);
    float balance = luaL_checknumber(L, 2);
    return new BankAccount(owner, balance);
}

int BankAccount_deposit(lua_State *L)
{
    BankAccount* account = luaW_check<BankAccount>(L, 1);
    float amount = luaL_checknumber(L, 2);
    account->deposit(amount);
    return 0;
}

static luaL_Reg BankAccount_table[] =
{
    { NULL, NULL }
};

static luaL_Reg BankAccount_metatable[] =
{
    { "deposit", BankAccount_deposit },
    { NULL, NULL }
};

int luaopen_BankAccount(lua_State* L)
{
    luaW_register<BankAccount>(L,
        "BankAccount",
        BankAccount_table,
        BankAccount_metatable,
        BankAccount_new // 如果您的类有默认构造函数,可以省略此参数,
                        // LuaWrapper 会为您生成一个默认的分配器。
    );
    return 1;
}

正如您看到的,使用这种方法,第一个参数是对象的实例。

2016-05-21 11:01:13