开发者

Overriding c++ method in lua and call it back in c++

开发者 https://www.devze.com 2023-02-05 16:27 出处:网络
I once have thought that I can override a class method in lua so that when I call that function in C++, it will do what has overriden in lua. I mean, like this :

I once have thought that I can override a class method in lua so that when I call that function in C++, it will do what has overriden in lua. I mean, like this :

C++ class


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

Assume that I have that class binded to lua so that in lua, I can use the object :


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

What I'm trying to achieve is something like this :

Lua file


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

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

C++ code


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;
}

In the code above, you can see that I'm trying to override the Person's method in lua and expect the overriden method to be called from c++. However, when i try it, the overriden method is not executed. What I'm trying to achieve is the overriden method is executed in C++. How do you achieve this?

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

I've thought a way to achieve this, but I'm not sure if this is good. My idea is the exported class should have a string representing the global variable name in lua that is used to hold the instance of this class. Like this:


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
  }
};

So, in lua, the object is responsible to implement shoutScript() and assign global var to object :


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

With codes above, I can achieve what I want (haven't tested it, though). But, is there any other, pro开发者_运维技巧per way to achieve what I want?


What we did in lqt, the automated binding of Qt to Lua, is that for each class that we bind, which has virtual methods, we create a proxy "shell" class, which registers itself into the Lua state.

So for your (simplified) class:

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

We generate the following class:

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();
};

We represent these objects in Lua using userdata. Each has it's own environment table, to which we point the __newindex and __index metamethods (__index function looks up in the environment and then in the class table). Using this, the user can store custom fields on the objects. He can also implement virtual functions, like this:

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

In our lqt_shell_Person::shout method, we first fetch the arguments, and then check whether there is a function shout in the environment table of the userdata. If there is, we call it with the arguments. If there isn't any, we call the original function. In case of abstract methods, we throw a Lua error.

Hope you find this useful.


Lua is "ideologically" different from C++. Lua is prototype-based OO language. C++ is class-based OO language. Lua can modify objects interface run-time, C++ can not modify objects type after object has been constructed.

So what-ever you do with your lua objects interface the changes do not reflect back to C++ program but stay in lua.

0

精彩评论

暂无评论...
验证码 换一张
取 消