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 Snippit 😛

    int 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! 🙂


Log in to reply