2012-06-19 12 views
9

mam zawijania funkcję C z Lua, używając API Lua Lua-C do 5.2:Jak utworzyć obiekt klasy w Lua-C API 5.2?

#include <lua.h> 
#include <lauxlib.h> 
#include <stdlib.h> 
#include <stdio.h> 

int foo_gc(); 
int foo_index(); 
int foo_newindex(); 
int foo_dosomething(); 
int foo_new(); 

struct foo { 
    int x; 
}; 

static const luaL_Reg _meta[] = { 
    {"__gc", foo_gc}, 
    {"__index", foo_index}, 
    {"__newindex", foo_newindex}, 
    { NULL, NULL } 
}; 
static const luaL_Reg _methods[] = { 
    {"new", foo_new}, 
    {"dosomething", foo_dosomething}, 
    { NULL, NULL } 
}; 

int foo_gc(lua_State* L) { 
    printf("## __gc\n"); 
    return 0; 
} 
int foo_newindex(lua_State* L) { 
    printf("## __newindex\n"); 
    return 0; 
} 
int foo_index(lua_State* L) { 
    printf("## __index\n"); 
    return 0; 
} 
int foo_dosomething(lua_State* L) { 
    printf("## dosomething\n"); 
    return 0; 
} 
int foo_new(lua_State* L) { 
    printf("## new\n"); 

    lua_newuserdata(L,sizeof(Foo)); 
    luaL_getmetatable(L, "Foo"); 
    lua_setmetatable(L, -2); 

    return 1; 
} 

void register_foo_class(lua_State* L) { 
    luaL_newlib(L, _methods); 
    luaL_newmetatable(L, "Foo"); 
    luaL_setfuncs(L, _meta, 0); 
    lua_setmetatable(L, -2); 
    lua_setglobal(L, "Foo"); 
} 

Gdy ten Lua:

local foo = Foo.new() 
foo:dosomething() 

... Widzę to wyjście (z błędem):

## new 
## __index 
Failed to run script: script.lua:2: attempt to call method 'dosomething' (a nil value) 

Co robię źle? Dzięki

+0

Spróbuj 'dla k, v w parach (getmetatable (foo)), aby wydrukować (k, v) koniec'. – lhf

+2

W Lua 5.2 można użyć 'luaL_setmetatable (L," Foo ")' zamiast 'luaL_getmetatable (L," Foo "); lua_setmetatable (L, -2); ' – lhf

+1

OT: Nie powinieneś używać' __' w identyfikatorach w C. – u0b34a0f6ae

Odpowiedz

8

Ok, ale działa. Musiałem dodać __index i __metatable do nowego metatable Foo „s, jak pokazano poniżej:

void register_foo_class(lua_State* L) { 
    int lib_id, meta_id; 

    /* newclass = {} */ 
    lua_createtable(L, 0, 0); 
    lib_id = lua_gettop(L); 

    /* metatable = {} */ 
    luaL_newmetatable(L, "Foo"); 
    meta_id = lua_gettop(L); 
    luaL_setfuncs(L, _meta, 0); 

    /* metatable.__index = _methods */ 
    luaL_newlib(L, _methods); 
    lua_setfield(L, meta_id, "__index");  

    /* metatable.__metatable = _meta */ 
    luaL_newlib(L, _meta); 
    lua_setfield(L, meta_id, "__metatable"); 

    /* class.__metatable = metatable */ 
    lua_setmetatable(L, lib_id); 

    /* _G["Foo"] = newclass */ 
    lua_setglobal(L, "Foo"); 
} 
3

Próbowałem odpowiadanie na rozwiązania, ale widocznie nie mam reputację do tego jeszcze, więc tu idzie oddzielny odpowiedź.

Twoje rozwiązanie jest całkiem ładne, ale nie pozwala na coś, co chciałbym zrobić: mieć zarówno "tablicopodobny" dostęp do obiektu i nadal mieć na nim funkcje. Spojrzeć na ten kod Lua:

Foo = {} 

mt = { 
__index = function(table, key) 
    print("Accessing array index ", tostring(key), "\n") 
    return 42 
end 
} 
setmetatable(Foo, mt) 

Foo.bar = function() 
    return 43 
end 

print(tostring(Foo[13]), "\n") 
print(tostring(Foo.bar()), "\n") 

--[[ 
Output: 
Accessing array index 13 
42 
43 
]]-- 

Rejestrowanie klasy przy użyciu swoje rozwiązanie nie wydaje się dopuszczać do tego, jak wpis __index są nadpisywane. Może nie mieć sensu posiadanie zarówno dostępu do tablicy, jak i dostępu do funkcji dla klasy, ale dla uproszczenia (oferowanie jednej funkcji C do rejestrowania obu typów klas) chciałbym używać tego samego kodu wszędzie. Czy ktokolwiek ma pojęcie, w jaki sposób można ominąć to ograniczenie, abym mógł stworzyć klasę z C, która ma zarówno funkcję Foo.bar(), ale także Foo [13]?

Powiązane problemy