【问题标题】:Overriding c++ method in lua and call it back in c++在lua中覆盖c ++方法并在c ++中调用它
【发布时间】:2011-06-12 21:06:52
【问题描述】:

我曾经想过我可以在 lua 中重写一个类方法,这样当我在 C++ 中调用该函数时,它就会执行在 lua 中重写的操作。我的意思是,像这样:

C++ 类


class Person {
public:
  Person(); // ctr
  virtual void shout(); // Meant to be overriden
};

假设我将该类绑定到 lua,以便在 lua 中使用该对象:


--Lua code
p = Person:new()
p:shout()

我想要实现的是这样的:

Lua 文件


--luafile.lua
p = Person:new() --instantiate

--override shout()
p.shout = function(self) print("OVERRIDEN!") end

C++ 代码


int main() {
  lua_State* l = lua_open();
  luaL_loadlibs(l);
  bind_person_class(l);

  luaL_dofile("luafile.lua");
  Person* p = (Person*) get_userdata_in_global(l, "p"); // get the created person in lua
  p->shout(); // expecting "OVERRIDEN" to be printed on screen

  lua_close(l);
  return 0;
}

在上面的代码中,您可以看到我试图在 lua 中覆盖 Person 的方法,并期望从 c++ 调用被覆盖的方法。但是,当我尝试它时,不会执行覆盖的方法。我想要实现的是在 C++ 中执行覆盖的方法。你是如何做到这一点的?

====================

我想了一种方法来实现这一点,但我不确定这是否好。我的想法是导出的类应该有一个字符串,表示 lua 中的全局变量名称,用于保存此类的实例。像这样:


class Person {
public:
  Person();
  string luaVarName; // lua's global variable to hold this class
  virtual void shout() { 
    luaL_dostring(luaVarName + ":shoutScript()"); // now shout will call shoutScript() in lua
  }
};

因此,在lua中,对象负责实现shoutScript()并将全局变量分配给对象:


--LUA
p = Person:new()
p.shoutScript = function(self) print("OVERRIDEN") end
p.luaVarName = "p"

使用上面的代码,我可以实现我想要的(虽然还没有测试过)。但是,还有其他合适的方法来实现我想要的吗?

【问题讨论】:

  • 你明白为什么第一个变体失败了吗?
  • @GMan:我想是因为我还没有真正重写该方法。 AFAIK,当您在 C++ 中调用方法(或函数)时,您指的是指令所在的地址。当一个函数被覆盖时,有一种机制可以引用另一个地址。因此,当我在 LUA 中“覆盖”它时,C++ 并不知道它,因此调用了真正的函数。 CMIIW。

标签: c++ class methods lua overriding


【解决方案1】:

我们在lqt(Qt 到 Lua 的自动绑定)中所做的是,对于我们绑定的每个具有虚拟方法的类,我们创建一个代理“shell”类,它将自己注册到 Lua 状态。

所以对于你的(简化的)类:

class Person {
public:
  virtual void shout(); // Meant to be overriden
};

我们生成以下类:

class lqt_shell_Person : public Person {
  lua_State *L;
public:
  lqt_shell_Person(lua_State *L); // registers itself into the Lua state
  virtual void shout();
};

我们在 Lua 中使用 userdata 来表示这些对象。每个都有自己的环境表,我们将__newindex 和__index 元方法指向它(__index 函数在环境中查找,然后在类表中查找)。使用它,用户可以在对象上存储自定义字段。他还可以实现虚函数,像这样:

p = Person.new()
function p:shout() print("Hello world!") end

在我们的lqt_shell_Person::shout方法中,我们首先获取参数,然后检查userdata的环境表中是否有函数shout。如果有,我们用参数调用它。如果没有,我们调用原始函数。如果是抽象方法,我们会抛出 Lua 错误。

希望你觉得这很有用。

【讨论】:

  • @Michael:谢谢。这是一个非常好的解决方案 :) 正是我正在寻找的。​​span>
【解决方案2】:

Lua 在“意识形态”上与 C++ 不同。 Lua 是prototype-based OO 语言。 C++ 是基于类的 OO 语言。 Lua 可以在运行时修改对象接口,C++ 不能在对象构建后修改对象类型。

因此,无论您对 lua 对象接口做什么,更改都不会反映回 C++ 程序,而是保留在 lua 中。

【讨论】:

  • 谢谢。这让我更清楚。但是,我真的很想知道其他(更优雅)的方式来实现我所描述的事情。或者我应该问更一般的问题:在 Lua 中实现对象级(在 C++ 中)变化的正确方法是什么?
猜你喜欢
  • 1970-01-01
  • 2011-10-04
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 2010-11-16
相关资源
最近更新 更多