2012-06-19 25 views
9

Tôi gói một hàm C với Lua, sử dụng API Lua-C cho Lua 5.2:Làm cách nào để tạo đối tượng lớp trong API Lua-C 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"); 
} 

Khi tôi chạy Lua này:

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

... Tôi thấy đầu ra này (có lỗi):

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

Tôi đang làm gì sai? Cảm ơn

+0

Thử 'for k, v theo cặp (getmetatable (foo)) in (k, v) end'. – lhf

+2

Trong Lua 5.2 bạn có thể sử dụng 'luaL_setmetatable (L," Foo ")' thay vì 'luaL_getmetatable (L," Foo "); lua_setmetatable (L, -2); ' – lhf

+1

OT: Bạn không nên sử dụng' __' trong số nhận dạng trong C. – u0b34a0f6ae

Trả lời

8

Ok, làm cho nó hoạt động. Tôi đã có thêm __index__metatable để metatable mới Foo 's, như hình dưới đây:

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

Tôi đã cố gắng trả lời giải pháp của bạn nhưng dường như tôi không có uy tín để làm như vậy, vì vậy ở đây đi một riêng biệt câu trả lời.

Giải pháp của bạn khá đẹp, nhưng nó không cho phép điều gì đó mà tôi muốn làm: Có cả truy cập "giống mảng" đối tượng và vẫn có chức năng trên đó. Có một cái nhìn vào mã Lua này:

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 
]]-- 

Đăng ký một lớp học sử dụng giải pháp của bạn dường như không cho phép này, vì mục __index bị ghi đè. Nó có thể không có ý nghĩa để có cả truy cập mảng và truy cập chức năng trên một lớp, nhưng vì mục đích đơn giản (cung cấp một hàm C để đăng ký cả hai loại lớp), tôi muốn sử dụng cùng một mã ở mọi nơi. Có ai có một ý tưởng làm thế nào hạn chế này có thể được phá vỡ, để tôi có thể tạo một lớp học từ C trong đó có cả một hàm Foo.bar() mà còn Foo [13]?

Các vấn đề liên quan