代码之家  ›  专栏  ›  技术社区  ›  Tom J Nowell

用Cug封装C++中使用的Lua对象

  •  2
  • Tom J Nowell  · 技术社区  · 15 年前

    目前我知道如何使用SWIG绑定在Lua中实例化并传递C++对象,我需要的是相反的。

    我使用的是Lua&C++&Sug。

    我有C++中的接口和LUA中的对象,它们实现了相同的工作并具有相同的结构的方法。我希望能够在Lua中实例化这些对象,但在C++中使用它们类似于它们的接口的指针传递它们。

    因此,我可以想象创建一个C++接口的实现,它将充当LUA对象的处理程序,但我不知道如何做这件事。该类将充当C++世界中的LUA对象代表或代理。

    为了澄清,我将从回答我提出的类似问题时使用的以下示例代码开始:

    C++代码:

    // Represents a generic bank account
    class Account {
        virtual void deposit(double amount) = 0;
    };
    

    LUA代码:

    SavingsAccount = { balance = 0 }
    SavingsAccount.deposit = function(amount)
        SavingsAccount.balance = SavingsAccount.balance + amount
    end
    
    -- Usage
    a = SavingsAccount
    a.balance = 100
    a.deposit(1000)
    

    现在说我有一个C++类,叫做银行:

    class Bank {
        void AddAccount(Account* a);
    };
    

    我希望这里有一个在Lua中执行以下操作的机制:

    SavingsAccount = { balance = 0 }
    SavingsAccount.deposit = function(amount)
        SavingsAccount.balance = SavingsAccount.balance + amount
    end
    
    -- Usage
    a = SavingsAccount
    bank:AddAccount(a)
    

    如果我需要采取额外的步骤,例如实例化C++类来充当代理,并将它与所有的Lua函数等传递给LUA表,我可以想象它看起来像这样:

    C++代码:

    // Represents a generic bank account
    class ProxyAccount : public Account {
        virtual void deposit(double amount);
    };
    

    LUA代码:

    SavingsAccount = { balance = 0 }
    SavingsAccount.deposit = function(amount)
        SavingsAccount.balance = SavingsAccount.balance + amount
    end
    
    -- Usage
    a = SavingsAccount
    a.balance = 100
    a.deposit(1000)
    
    proxy = program.ProxyAccount()
    proxy.settable(a)
    bank:AddAccount(p)
    

    这里的问题是,我不知道如何实现proxyaccount类,甚至不知道settable的函数签名是什么样子的…

    3 回复  |  直到 15 年前
        1
  •  2
  •   Ramon Zarazua B.    15 年前

    从你的例子和讨论中可以看出,你希望Lua成为主要语言,C++是客户。问题是,lua-c接口并不是这样设计的,lua就是客户机,所有的工作都是用c编写的,这样lua就可以轻松地调用它。

    现在,重要的问题是:为什么您不希望对象有一个C表示,而更喜欢用Lua表示?因为C++是一种非常低级的语言,对象定义必须是静态的,而LUA动态地定义它的“对象”,所以LUA更容易适应C++对象。

    我看到的另一个问题是,您似乎正在用 非常 面向对象的方式。记住,尽管Lua可以伪造面向对象的概念,但它不是作为面向对象的语言构建的,不应该主要作为一种语言使用。如果您想要一种完全面向对象的脚本语言,请使用python。

    现在如果你 真的? 如果你想用另一种方式来做,考虑到其他的选择对你不起作用,那么我建议你将Lua对象作为协程,这将允许你:

    • 保留对象的表示形式 在C++中(LuaSuth*)
    • 具有相同“对象类型”的多个单独实例
    • Lua负责清理

    但是,缺点是:

    • 作用于“对象”的所有函数 需要通过Lua API来实现这一点
    • 没有简单/快速的方法来识别不同的Lua类型(您 可以使用元表)
    • 实施起来相当麻烦,而且很难进行解密。

    编辑: 下面介绍如何将接口公开给脚本中的对象,每个对象实例都将运行一个新的lua_状态,并单独运行其脚本,从而允许“对象成员数据”只是脚本实例中的全局数据。为对象方法实现API的过程如下:

    int move(lua_State * L)
    {
      int idx = lua_getglobal(L, "this");
      assert(!lua_isnull(-1));
      AIObject * obj = static_cast<AIObject *>(lua_touserdata(L, -1));
      lua_pop(1);
      //Pop the other parameters
      obj->move(/*params*/);
    }
    
        2
  •  3
  •   Zack The Human Kunal    15 年前

    我不熟悉Swig(我知道它是什么,但从未用过),所以这可能不是你要找的答案。

    我一直致力于C++项目,并已经成功地使用了 luabind .它允许你 subclass C++ objects with Lua objects . 你可能想试试看它是否适合你。

        3
  •  1
  •   Aaron Saarela    15 年前

    您可以绑定任何您想要Lua的C函数并从那里调用它。你可以在这个函数中定义你期望的合同在你的脚本和C++代码之间。例如,以下内容可以满足您的需要。您需要将元表信息添加到您的lua表中,这样您就可以区分不同的lua对象类型。

    int lua_AddBankAccount(lua_State* L, int pos)
    {
        // Assume you've created metadata for your Lua objects.
        if (IsAccount(L, pos))
        {
           // process your 'Account' Lua instance.
        }
        else
        {
           // error - tried to add a non-Account.
        }
    }
    

    您可以使用swig进一步绑定任意的C方法,但基本上是相同的。