Cpp 对象绑定

lua-users home
wiki

在 C++ 对象上交替使用 Lua 和 C++

尝试从 Lua 访问您的 C++ 对象(不使用任何项目附加组件)?您可以将 C++ 方法公开给 Lua 脚本,并允许脚本使用 lightuserdata 传递指针来调用对象内部的方法。请注意,我正在使用 * SimplerCppBinding 页面中的 luna.h。

首先,从您要公开给 Lua 的对象开始 - 这是一个具有整数属性和字符串的简单类。

object.cpp

#include "object.h"

GameObject::GameObject(int x){
  attribute = x;
}

int GameObject::getAttr(){
  return (int)attribute;
}

void GameObject::setAttr(int set){
  attribute = set;
}

void GameObject::setMessage(const char* new_message){
  message.assign(new_message);
}

const char* GameObject::getMessage(){
  return message.c_str();
}
  
GameObject::~GameObject(){
  printf("deleted Object (%p)\n", this);
}

object.h

/**
 * This is the main object that is actually used in the C++ code.
 * It is to be manipulated by Lua through the Lua wrapper object (which will
 * contain a pointer to this object).
 */
#ifndef _object_h_
#define _object_h_

// Notice that I don't need ANY Lua stuff in here...
#include <stdio.h>
#include <string>

class GameObject{
public:
  GameObject(int x);
  ~GameObject();

  int getAttr(void);
  void setAttr(int balance);

  void setMessage(const char* new_message);
  const char* getMessage(void);
private:
  int attribute;
  std::string message;
};
#endif

在您拥有现在可以通过 C++ 修改的对象后,您需要编写一个类来将该对象公开给 Lua。

luaobject.cpp

#include "luaobject.h"

LuaGameObject::LuaGameObject(lua_State *L){
  real_object = (GameObject*)lua_touserdata(L, 1);
}

void LuaGameObject::setObject(lua_State *L){
  real_object = (GameObject*)lua_touserdata(L, 1);
}

int LuaGameObject::setAttr(lua_State *L){
  real_object->setAttr((int)luaL_checknumber(L, 1));
  return 0;
}
int LuaGameObject::getAttr(lua_State *L){
  lua_pushnumber(L, real_object->getAttr());
  return 1;
}

int LuaGameObject::setMessage(lua_State *L){
  real_object->setMessage(lua_tostring(L, 1));
  return 0;
}
int LuaGameObject::getMessage(lua_State *L){
  lua_pushstring(L, real_object->getMessage());
  return 1;
}

LuaGameObject::~LuaGameObject(){
  printf("deleted Lua Object (%p)\n", this);
}

luaobject.h

/**
 * This is the wrapper around the C++ object found in object.cc
 * Everything this object has done to it is passed on FROM Lua to the real C++
 * object through the pointer 'real_object'
 * Notice that I kept the function names the same for simplicity.
 */
#ifndef _luaobject_h_
#define _luaobject_h_

// Need to include lua headers this way
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}

// I am using luna
#include "luna.h"
// The header file for the real C++ object
#include "object.h"

class LuaGameObject{
public:
  // Constants
  static const char className[];
  static Luna<LuaGameObject>::RegType methods[];

  // Initialize the pointer
  LuaGameObject(lua_State *L);
  ~LuaGameObject();
  void setObject(lua_State *L);

  // Methods we will need to use
  int getAttr(lua_State *L);
  int setAttr(lua_State *L);
  int getMessage(lua_State *L);
  int setMessage(lua_State *L);
private:
  // The pointer to the 'real object' defined in object.cc
  GameObject* real_object;
};
#endif

好了,现在我们有了 Lua 访问此对象的方法,让我们将它们整合在一起。请注意,这里的关键是使用 lightuserdata 将指针传递给 Lua。

main.cpp

/**
 * Main program to actually run the Lua code against the C++ object
 */
#include "object.h"
#include "luaobject.h"

// Define the Lua ClassName
const char LuaGameObject::className[] = "LuaGameObject";

// Define the methods we will expose to Lua
// Check luaobject.h for the definitions...
#define method(class, name) {#name, &class::name}
Luna<LuaGameObject>::RegType LuaGameObject::methods[] = {
   method(LuaGameObject, setAttr),
   method(LuaGameObject, getAttr),
   method(LuaGameObject, getMessage),
   method(LuaGameObject, setMessage),
   {0,0}
};

int main(int argc, char *argv[]){
  // Init Lua
  lua_State *L = lua_open();
  luaopen_base(L);
  luaopen_table(L);
  luaopen_io(L);
  luaopen_string(L);
  luaopen_math(L);
  luaopen_debug(L);

  // Register the LuaGameObject data type with Lua
  Luna<LuaGameObject>::Register(L);

  // In C++ - Create a GameObject for use in our program
  GameObject temp(20);
  temp.setMessage("I'm set in C++");
  
  // Push a pointer to this GameObject to the Lua stack
  lua_pushlightuserdata(L, (void*)&temp);
  // And set the global name of this pointer
  lua_setglobal(L,"gameobject");

  printf("In C: %p => %d, %s\n", &temp, temp.getAttr(), temp.getMessage());

  printf("Loading lua----------\n");
  luaL_loadfile(L, argv[1]);
  printf("lua is loaded--------\n");

  printf("Running lua----------\n");
  lua_pcall(L, 0, 0, 0);
  printf("Lua is done----------\n");
  //lua_setgcthreshold(L, 0);  // collected garbage

  luaL_loadfile(L, argv[1]);
  printf("Running lua2---------\n");
  lua_pcall(L, 0, 0, 0);
  printf("Lua is done2---------\n");

  // GC + Close out Lua
  lua_close(L);

  printf("In C++: %p => %d, %s\n", &temp, temp.getAttr(), temp.getMessage());
  return 0;
}

现在,让我们运行一个像这样的测试程序

gameobject.lua

--[[ 
   gameobject comes from the global parameters and is a pointer to
   the REAL C++ data.  This is saved as lightuserdata in Lua and we preserve
   this pointer in the LuaGameObject.  From there, we can manipulate
   ANYTHING from this pointer.
--]]

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

-- This function uses the getX() methods in our target class
function LuaGameObject:show()
  printf("LuaGameObject attribute = %d - %s\n", self:getAttr(), self:getMessage())
end

-- Start up a new LuaGameObject wrapper class and pass the global gameobject
-- C++ lightuserdata pointer into it
b = LuaGameObject(gameobject)

-- Call a Lua function on this object
b:show()

print('Now to work on the C++ object')
-- Modify some of the parameters (gameobject->modify)
b:setAttr(120)
b:setMessage('Hey - Lua changes a string!')
print('Lua is done changing...')
b:show()

最后,以下是发生的事情

./main gameobject.lua
In C: 0xbfb1d630 => 20, I'm set in C
Loading lua----------
lua is loaded--------
Running lua----------
LuaGameObject balance = 20 - I'm set in C
Now to work on the C++ object
Lua is done changing...
LuaGameObject attribute = 120 - Hey - Lua changes a string!
Lua is done----------
Running lua2---------
LuaGameObject attribute = 120 - Hey - Lua changes a string!
Now to work on the C++ object
Lua is done changing...
LuaGameObject attribute = 120 - Hey - Lua changes a string!
Lua is done2---------
deleted Lua Object (0x80642d0)
deleted Lua Object (0x8064c40)
In C: 0xbfb1d630 => 120, Hey - Lua changes a string!
deleted Object (0xbfb1d630)

希望您发现此示例有用 - Lua 太棒了!


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009 年 5 月 6 日上午 8:33 GMT (差异)