Reputation: 94
I would like to implement Object Orientated Programming in my lua interpreter, I understand that I can return a lua table from a C Function. And I would like the table that is returned to be full of C functions.
player = getClosestPlayer();
player.walkTo();
where both getClosestPlayer() and walkTo() are C functions.
From the C function for walkTo(), how do I differentiate between object types?
I would prefer every object to have a gid that I can use to identify it (player.gid) but how do I access that gid from the c function?
In other words, what is the equivalent of self.gid from C code?
int l_playerWalkTo(lua_State* functionState){
int gid = // self.gid?
// do something with gid
}
One way I could do this is to upvalue every single function in the table, but is there a more elegant way to do it?
Upvotes: 1
Views: 565
Reputation: 94
Many thanks to macroland for his answer, I just though I would clear up what he has said. This lua wrapper can be used to implement c++ classes into Lua: https://bitbucket.org/alexames/luawrapper/overview
A great example of the usage of this library can be found here: https://bitbucket.org/alexames/luawrapperexample/src/
Here is the code (taken straight from the example site)
Lua:
alicesaccount = BankAccount.new("Alice", 100)
alicesaccount:deposit(20);
alicesaccount:deposit(30);
alicesaccount:deposit(40);
c++:
BankAccount* BankAccount_new(lua_State *L)
{
const char* owner = luaL_checkstring(L, 1);
float balance = luaL_checknumber(L, 2);
return new BankAccount(owner, balance);
}
int BankAccount_deposit(lua_State *L)
{
BankAccount* account = luaW_check<BankAccount>(L, 1);
float amount = luaL_checknumber(L, 2);
account->deposit(amount);
return 0;
}
static luaL_Reg BankAccount_table[] =
{
{ NULL, NULL }
};
static luaL_Reg BankAccount_metatable[] =
{
{ "deposit", BankAccount_deposit },
{ NULL, NULL }
};
int luaopen_BankAccount(lua_State* L)
{
luaW_register<BankAccount>(L,
"BankAccount",
BankAccount_table,
BankAccount_metatable,
BankAccount_new // If your class has a default constructor you can omit this argument,
// LuaWrapper will generate a default allocator for you.
);
return 1;
}
As you can see, Using this method the first argument is an instance of the object
Upvotes: 1
Reputation: 1025
I had the similar problem and the way I resolved is:
1) Create an interface class in C++ with abstract methods
class LuaInterfaceOOP
{
public:
LuaInterfaceOOP(){}
virtual CObject* clone(void) const=0;
virtual wxString type(void)=0;
virtual wxString ToString(void)=0;
wxString GetType()return this->type();
wxString GetToString() return this->ToString();
virtual ~CObject(){}
};
2) Any class that you want to expose to Lua should implement this to be consistent.
class MyClass: public LuaInterfaceOOP
{
public:
wxString type() { return "MyClass";}
wxString ToString();
};
3) When you write a wrapper for this class make sure
int MyClass_toString(lua_State* L)
{
MyClass* mc= luaW_check<MyClass>(L, 1);
const char* str=mc->ToString().c_str();
lua_pushstring(L, str);
return 1;
}
int MyClass_type(lua_State* L)
{
lua_pushstring(L,"MyClass");
return 1;
}
4) Overload the type function provided by Lua, for you the important part will be:
case LUA_TUSERDATA:
{
wxString str1;
if(lua_getmetatable(L,idx)) // Stk: Userdata Table
{
lua_getfield(L,-1,"type"); // Stk: Userdata Table function
if(!lua_pcall(L,0,1,0)) // Stk: Userdata Table string
{
str1<<lua_tostring(L,-1);
wxReturnStr<<str1;
lua_pop(L,2);// Stk: Userdata
}
else //stk: Userdata table
{
lua_pop(L,1);
wxReturnStr<<"userdata"; //stk: Userdata
}
}else wxReturnStr<<"userdata";
break;
}
EDIT 1: Adding code to wrap C++ funcs to Lua
static luaL_Reg MyClass_table[] = {
{ NULL, NULL }
};
static luaL_Reg Myclass_metatable[] = {
{"type", Myclass_type},
{"__tostring", Myclass_toString},
{ NULL, NULL }
};
Finally,
static int luaopen_MyClass(lua_State* L)
{
luaW_register<MyClass>(L, "MyClass", MyClass_table, MyClass_metatable, MyClass_new);
return 1;
}
Now in Lua you can use an expression such as if(type(aclass)=="MyClass")
I am not sure if these steps are the best way, but so far it worked.
Upvotes: 0