【问题标题】:OOP in Lua From C来自 C 的 Lua 中的 OOP
【发布时间】:2016-05-21 02:46:55
【问题描述】:

我想在我的 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
}

我可以做到这一点的一种方法是对表中的每个函数进行升值,但有没有更优雅的方法来做到这一点?

【问题讨论】:

    标签: c++ c oop lua


    【解决方案1】:

    非常感谢macroland的回答,尽管我会澄清他所说的话。 这个 lua 包装器可用于在 Lua 中实现 c++ 类: https://bitbucket.org/alexames/luawrapper/overview

    可以在此处找到使用此库的一个很好的示例: https://bitbucket.org/alexames/luawrapperexample/src/

    这是代码(直接取自示例网站)

    卢阿:

    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 // If your class has a default constructor you can omit this argument,
                            // LuaWrapper will generate a default allocator for you.
        );
        return 1;
    }
    

    如您所见,使用此方法的第一个参数是对象的实例

    【讨论】:

    • 这是将 C++ 包装到 Lua 的方式,您可以在网上找到很多示例。另一方面,Lua 语句 if(type(ba)=="BankAccount') 仍然不起作用
    • 我通过将 typedef'd 的整数推送到其他类型作为我的“GID”来实现这一点
    【解决方案2】:

    我遇到了类似的问题,我的解决方法是:

    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") 等表达式

    我不确定这些步骤是否是最好的方法,但到目前为止它确实有效。

    【讨论】:

    • 什么是luaW_check?我在 lua 手册中似乎找不到它。
    • 有了这个库,我可以把整个类推入 lua 吗?然后它会回调我在类中相对于实例的所有 C++ 函数?是这样的吗?
    • 使用你的结构,是否可以调用 MyClass.type()?成员函数的第一个参数是对象本身的实例吗?类似于lua的自我?抱歉,如果您已经回答了我的问题,我只是还没有看到。
    • 啊,是的!我知道了!第一个参数是对象的一个​​实例!一个很好的例子可以在这里找到:bitbucket.org/alexames/luawrapperexample/src/…。非常感谢!
    猜你喜欢
    • 2013-12-04
    • 2017-06-09
    • 2013-08-19
    • 2014-08-06
    • 2016-01-02
    • 2017-03-15
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多