Simple Cpp Binding

lua-users home
wiki

Description

Here is an example of a Lua binding for a simple C++ class. If you prefer, you can factor out all the nasty bits and put them in a template. SimplerCppBinding shows how to do this using Luna for Lua 5.0

C++ code




extern "C" {

#include "lua.h"

#include "lauxlib.h"

#include "lualib.h"

}



class Account {

  public:

    Account(double balance)      { m_balance = balance; }

    void deposit(double amount)  { m_balance += amount; }

    void withdraw(double amount) { m_balance -= amount; }

    double balance(void)         { return m_balance; }

  private:

    double m_balance;

};



class LuaAccount {

    static const char className[];

    static const luaL_reg methods[];



    static Account *checkaccount(lua_State *L, int narg) {

      luaL_checktype(L, narg, LUA_TUSERDATA);

      void *ud = luaL_checkudata(L, narg, className);

      if(!ud) luaL_typerror(L, narg, className);

      return *(Account**)ud;  // unbox pointer

    }



    static int create_account(lua_State *L) {

      double balance = luaL_checknumber(L, 1);

      Account *a = new Account(balance);

      lua_boxpointer(L, a);

      luaL_getmetatable(L, className);

      lua_setmetatable(L, -2);

      return 1;

    }

    static int deposit(lua_State *L) {

      Account *a = checkaccount(L, 1);

      double amount = luaL_checknumber(L, 2);

      a->deposit(amount);

      return 0;

    }

    static int withdraw(lua_State *L) {

      Account *a = checkaccount(L, 1);

      double amount = luaL_checknumber(L, 2);

      a->withdraw(amount);

      return 0;

    }

    static int balance(lua_State *L) {

      Account *a = checkaccount(L, 1);

      double balance = a->balance();

      lua_pushnumber(L, balance);

      return 1;

    }

    static int gc_account(lua_State *L) {

      Account *a = (Account*)lua_unboxpointer(L, 1);

      delete a;

      return 0;

    }



  public:

    static void Register(lua_State* L) {

      lua_newtable(L);                 int methodtable = lua_gettop(L);

      luaL_newmetatable(L, className); int metatable   = lua_gettop(L);



      lua_pushliteral(L, "__metatable");

      lua_pushvalue(L, methodtable);

      lua_settable(L, metatable);  // hide metatable from Lua getmetatable()



      lua_pushliteral(L, "__index");

      lua_pushvalue(L, methodtable);

      lua_settable(L, metatable);



      lua_pushliteral(L, "__gc");

      lua_pushcfunction(L, gc_account);

      lua_settable(L, metatable);



      lua_pop(L, 1);  // drop metatable



      luaL_openlib(L, 0, methods, 0);  // fill methodtable

      lua_pop(L, 1);  // drop methodtable



      lua_register(L, className, create_account);

    }

};



const char LuaAccount::className[] = "Account";



#define method(class, name) {#name, class::name}



const luaL_reg LuaAccount::methods[] = {

  method(LuaAccount, deposit),

  method(LuaAccount, withdraw),

  method(LuaAccount, balance),

  {0,0}

};



int main(int argc, char* argv[])

{

  lua_State *L = lua_open();



  luaopen_base(L);

  luaopen_table(L);

  luaopen_io(L);

  luaopen_string(L);

  luaopen_math(L);

  luaopen_debug(L);



  LuaAccount::Register(L);



  if(argc>1) lua_dofile(L, argv[1]);



  lua_close(L);

  return 0;

}



Compiling the Code

This code can be compiled for Lua 5.0 as follows:


g++ -o test  account.cc -L/usr/local/lib -llua -llualib

Lua Test Code

function printf(...) io.write(string.format(unpack(arg))) end



local a = Account(100)

printf("Account balance = $%0.02f\n", a:balance() )

a:deposit(50.30)

printf("Account balance = $%0.02f\n", a:balance() )

a:withdraw(25.10)

printf("Account balance = $%0.02f\n", a:balance() )



Test Code Output


$ ./test account.lua

Account balance = $100.00

Account balance = $150.30

Account balance = $125.20


RecentChanges · preferences
edit · history
Last edited May 5, 2012 2:54 am GMT (diff)