【问题标题】:Use of metatables in LuaLua 中元表的使用
【发布时间】:2011-12-31 18:06:01
【问题描述】:

我正在尝试在 Lua 脚本中实现对象表示法。 以下是我使用 C API 成功完成的工作:

  • 我创建了一个新的全局表“Test”作为一个类,并在其中添加了一个字段“new”,指向一个用 C 编写的函数 即我可以在 lua 代码中执行此操作:“local obj = Test.new()”(它调用函数“new”)

  • “new”C 函数创建并返回一个新表,并将其中的函数注册为字段(例如“add”、“count”...) 即我可以这样做:"obj:add("mike")" 和 "obj:count()"(obj 作为第一个参数传递,带有 ":" 符号)

2 个问题:

1) 一切都按预期工作,但我想知道的是:在我的情况下使用元表有什么好处? 我到处都看到元表可以帮助我实现我试图做的事情,但我不明白它们在哪里有用? 将字段作为方法添加到表中不正确? 元表如何帮助我(如果添加为我的表元表)?

2) 事实上,我正在尝试在 Lua 中重现 C++ 的行为。 例如,当我用 C++ 编写时:“Test *obj = new Test();” 我希望 C++ 和 Test 的构造函数返回一个 Test 实例的指针。 这正是我尝试 Lua 为我做的事情。

问题是在这种情况下我使用了一个表,作为“new”的返回,而不是一个指针,所以我可以稍后使用 Lua(使用它的字段)调用它的方法,就像一个标准的 C++ 对象(使用运算符 ->)。

为了能够在 C 函数中检索我的类的实际指针,我在“new”返回的表中添加了一个字段“ptr”(轻用户值)。没有它,我将只能在我的 C 函数中操作 Lua 表,仅此而已(因此不再对实际指针进行方法调用)。

我的第二个问题是,这样做是否正确? 您对如何在没有这个“ptr”字段的情况下在任何地方操作我的指针有更好的想法吗?

谢谢,

尼古拉斯。

【问题讨论】:

  • @kikito:先决条件是什么? C++(和许多其他语言)可以很好地与 C 代码互操作。
  • 我的意思是,你需要使用 C 吗?您可以在纯 Lua 中执行 OOP,不涉及 C。
  • 当然可以,但我需要能够使用 C API 操作 C 数据(这就是重点)。

标签: lua


【解决方案1】:

主要原因是你得到了 __index 元方法。 没有它,对象的每个实例都必须具有与之关联的所有功能:这会使表变得很大;并使用大量内存。

local methods = { 
    foo = function() return "foo" end ;
    bar = function() return "bar" end ;
    bob = function() return "bob" end ;
    hen = function() return "hen" end ; 
}

所以你有一个

function new_no_mt ( )
    local t = {}
    for k , v in pairs ( methods ) do t [ k ] = v end
    return t
end

local mt = { __index = methods ; }
function new_mt ( )
    return setmetatable ( { } , mt )
end

还有其他好处;

  • 定义运算符;
  • 通过比较元表轻松进行类型比较。
  • 更改元表中的方法会更改所有对象的方法,但更改一个对象只会更改该对象的方法。

否则,您尝试做的事情听起来像是用户数据的完美情况。 只有当你有一个 __index 元方法时,用户数据才能被索引(没有表可以放入方法)

【讨论】:

  • 好的,所以你建议我让 Test.new 返回一个用户数据(完整的还是轻量级的?)并为其分配一个元表?如何向我的用户数据添加 __index 元方法?
  • 完整用户数据(轻量级用户数据共享所有实例的元表);在你的 lua_open 函数中使用 luaL_newmetatable 来创建一个元表;然后当你制作用户数据时;使用 luaL_getmetatable & lua_setmetatable
【解决方案2】:

在我的情况下使用元表有什么好处?

这是一个。

Test.new = function() end

我刚刚破坏了您全局创建新Test 对象的能力。如果您使用元表保护Test,我将不得不真正努力才能做到这一点。

这是另一个:

local myTest = Test()

如果没有元表,您将无法做到这一点(重载 __call 元方法)。 Lua 语法看起来比调用Test.new 更自然。

还有一个:

local testAdd = Test() + Test()

运算符重载。如果没有元表,您将无法做到这一点。

还有:

这正是我尝试 Lua 为我做的事情。

这里有一个提示:不要。

不同的语言有不同的原因。你应该在 Lua 中以 Lua 的方式做事,而不是 C++ 的方式。我可以理解想要提供某些 C++ 机制(如重载等),但您不应该仅仅因为 C++ 使用而使用 new

此外,还有很多库可以为您完成这项工作。 SWIGLuabind 是两个大的。

【讨论】:

  • 感谢您的回答。如何使用元表保护 Test 免受“Test.new = function() end”黑客攻击?另外,如何使用 C API 将元表附加到我的轻量级用户数据?
  • 此外,如果我的 new 或 __call 元方法返回一个轻量的用户数据,我以后可以调用它的方法吗?我认为该用户数据的元表将在某处发挥作用,对吗?在这种情况下,我该如何实现?
猜你喜欢
  • 2018-11-14
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 2014-08-12
  • 2011-07-30
相关资源
最近更新 更多