C Klasse in LUA verwenden
-
Guten Tag,
Ich hätte zwei kleine Fragen an euch im Bezug C++ Klasse(n) mit/in Lua verwenden:Wie kann ich die erstelle klasse für LUA regestrieren?
Hier mal ein kleines Beispiel:class Person { private: std::string szName; int iAge; public: Person( void ) { } void setAge( int age ) { this->iAge = age; } void setName( std::string name ) { if( !( char* )name.c_str() ) return; this->szName = name; } int getAge( void ) { return this->iAge; } std::string getName( void ) { return this->szName; } };
Mich würde ebenso interessieren wie ich den Konstruktor einmal global für LUA anlegen kann sprich das ich in der .lua Datei es so aufrufen könnte:
-- Test-Script -- nennen wir die globale Instanz Peter Peter:setAge(20) Peter:setName("Peter Müller") -- un würde ich gerne einen neue Instanz anlegen -- etwa so(?) Ina = new Person() Ina:setAge(19) Ina:setName("Ina Schmitz")
Wäre echt super, wenn mir jemand helfen könnte!
Viele liebe Grüße
-
Hast du dich schon mit der Lua C API bzw einen Wrapper (zB luabind) beschaefftigt ?
-
Ja natürlich hab ich mich ein wenig in den Umgang mit LUA eingelesen.
Normale Funktionen etc, sind ja einfach zu erstellen/regestrieren.
Falls du es dennoch nicht glaubst, hier mal ein kleiner Snippitint lua_getCount( lua_State* l ) { lua_pushnumber( l, setCount() ); return 1; } int lua_setCount( lua_State* l ) { int i = luaL_checkint( l, 1 ); if( i >= -1 ) { setCount( i ); } return 0; } int main( void ) { pLua->addScript( "Test", pLua->getCurrentFilePath( "random.lua" ) ); lua_register( pLua->getInstance(), "setCount", lua_setCount ); lua_register( pLua->getInstance(), "getCount", lua_getCount ); pLua->exec( "Test" ); std::cin.get(); return 0; }
-
Hast du dich schonmal mit Metatables in Lua auseinandergesetzt?
Du kannst deine Klasse in C++ zu Userdata in Lua umwandeln und diesen einen Metatable zuordnen, welcher den möglichen Umgang damit definiert. Dazu gehört z.B. welche Funktion aufgerufen wird, wenn die Userdata in Lua zerstört/vom GC aufgeräumt werden, was bei Addition oder Index/Feld-Zugriff passiert, usw. Im Grunde ist der Metatable der public Bereich einer Klasse und die Userdata eine Variable im privaten Bereich.
-
Ein Beispiel:
// Lua C API #include <lua.hpp> // C++ input/output streams #include <iostream> // MyObject as C++ class class MyObject{ private: double x; public: MyObject(double x) : x(x){} void set(double x){this->x = x;} double get() const{return this->x;} }; // MyObject identifier for the Lua metatable #define LUA_MYOBJECT "MyObject" // Create & return MyObject instance to Lua int myobject_new(lua_State* L){ double x = luaL_checknumber(L, 1); *reinterpret_cast<MyObject**>(lua_newuserdata(L, sizeof(MyObject*))) = new MyObject(x); luaL_setmetatable(L, LUA_MYOBJECT); return 1; } // Free MyObject instance by Lua garbage collection int myobject_delete(lua_State* L){ delete *reinterpret_cast<MyObject**>(lua_touserdata(L, 1)); return 0; } // MyObject member functions in Lua int myobject_set(lua_State* L){ (*reinterpret_cast<MyObject**>(luaL_checkudata(L, 1, LUA_MYOBJECT)))->set(luaL_checknumber(L, 2)); return 0; } int myobject_get(lua_State* L){ lua_pushnumber(L, (*reinterpret_cast<MyObject**>(luaL_checkudata(L, 1, LUA_MYOBJECT)))->get()); return 1; } // Register MyObject to Lua void register_myobject(lua_State* L){ lua_register(L, LUA_MYOBJECT, myobject_new); luaL_newmetatable(L, LUA_MYOBJECT); lua_pushcfunction(L, myobject_delete); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, myobject_set); lua_setfield(L, -2, "set"); lua_pushcfunction(L, myobject_get); lua_setfield(L, -2, "get"); lua_pop(L, 1); } // Program entry int main(int argc, char** argv){ if(argc > 1){ lua_State*L = luaL_newstate(); luaL_openlibs(L); register_myobject(L); if(luaL_dofile(L, argv[1])) std::cerr << lua_tostring(L, -1); lua_close(L); }else std::cerr << "Expected filename from command line!"; return 0; }
local obj = MyObject(42) print(obj:get()) -- 42 obj:set(-1.5) print(obj:get()) -- -1.5
-
Vielen lieben dank für diene Antwort und dem Bespiel!
Aber eine Frage hätte ich noch, hast du/Ihr eventuell eine Ahnung, warum ich die Funktion lua_newmetatable besitze aber nicht luaL_newmetatable?Liebe Grüße
-
Sowohl Lua Version 5.1 als auch 5.2 haben nicht lua_newmetatable, aber luaL_newmetatable. Etwa benutzt du eine sehr alte Lua Version oder hast anderswo etwas falsch gemacht. Eine Fehlermeldung wäre hilfreicher als "geht nicht".
luaL_* Funktionen sind lediglich Makros um die normalen Lua C Funktionen.
luaL_newmetatable stellt sicher, dass im Registry-Table auf dem Stack (am Pseudo-Index) ein Table bei genannten Feldnamen existiert und schiebt eine Referenz darauf oben auf den Stack.
-
Du hattest recht. Meine LUA Version war 5.0. Es funktioniert nun. Vielen dank für deine Hilfe!