2011-01-21 14 views
6

Una vez pensé que puedo anular un método de clase en lua para que cuando llame a esa función en C++, haga lo que se ha anulado en lua. Es decir, como esto:Reemplazando el método C++ en lua y devolviéndolo a C++

clase de C++


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

Supongamos que tengo esa clase enganchan a lua para que en lua, puedo utilizar el objeto:


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

Lo que Estoy tratando de lograr algo como esto:

Lua archivo


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

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

código 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; 
} 

En el código anterior, se puede ver que estoy tratando de reemplazar el método de la persona en lua y esperar que el método evitado para llamar desde C++. Sin embargo, cuando lo intento, el método reemplazado no se ejecuta. Lo que intento lograr es que el método modificado se ejecute en C++. ¿Cómo lo logras?

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

he pensado en una forma de lograr esto, pero no estoy seguro de si esto es bueno. Mi idea es que la clase exportada debe tener una cadena que represente el nombre de la variable global en lua que se usa para contener la instancia de esta clase. De esta manera:


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

Así pues, en Lua, el objeto es responsable de implementar shoutScript() y asignar var global para oponerse:


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

Con códigos anteriores, puedo lograr lo que quiero (refugio 't probado, sin embargo). Pero, ¿hay alguna otra forma adecuada de lograr lo que quiero?

+0

¿Entiende por qué falla la primera variación? – GManNickG

+0

@GMan: Creo que porque realmente no he anulado el método. AFAIK, cuando llama a métodos (o funciones) en C++, se refiere a una dirección donde se encuentra la instrucción. Y hay un mecanismo para referirse a otra dirección cuando se anula una función. Entonces, cuando lo "anulo" en LUA, C++ no lo sabe, por lo que se llama a la función real. CMIIW. – Radi

Respuesta

3

Lo que hicimos en lqt, la unión automática de Qt a Lua, es que para cada clase que vinculamos, que tiene métodos virtuales, creamos una clase proxy "shell", que se registra en el estado Lua.

Así que para su clase (simplificado):

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

Generamos la clase siguiente:

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

Representamos estos objetos en Lua usando datos de usuario.Cada uno tiene su propia tabla de entorno, a la que señalamos los __newindex y __index metamethods (la función __index busca en el entorno y luego en la tabla de clases). Al usar esto, el usuario puede almacenar campos personalizados en los objetos. También puede implementar funciones virtuales, como esto:

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

En nuestro método lqt_shell_Person::shout, primero buscar a los argumentos, y luego comprobar si hay una función shout en la tabla de entorno de la datos de usuario. Si hay, lo llamamos con los argumentos. Si no hay ninguno, llamamos a la función original. En el caso de métodos abstractos, lanzamos un error de Lua.

Espero que le sea útil.

+0

@Michael: Gracias. Esa es una muy buena solución :) exactamente lo que estoy buscando. – Radi

2

Lua es "ideológicamente" diferente de C++. Lua es prototype-based OO idioma. C++ es un lenguaje OO basado en clases. Lua puede modificar el tiempo de ejecución de la interfaz de objetos, C++ no puede modificar el tipo de objetos después de que se haya construido el objeto.

Así que haga lo que haga con su interfaz de objetos lua, los cambios no se reflejan en el programa C++ sino que permanecen en lua.

+1

Gracias. Esto hace las cosas más claras para mí. Sin embargo, realmente quiero saber otra forma (más elegante) de lograr las cosas que he descrito. O tal vez debería haber preguntado algo más general: ¿Cuál es la forma correcta de implementar la variación a nivel de objeto (en C++) en Lua? – Radi