Lua C API-从C++; 我尝试实例化并使用C++中的Lua类对象。 Lua类的定义如下 myclass = {} function myclass:new(o) o=o or {} setmetatable(o,self) self.__index=self return o end function myclass:init() self.something = 0 end function myclass:perform() self.something = self.something + 0.5 return performsomething(self.something) end 在C++中实例化对象,我做以下操作: lua_getglobal(L,"myclass"); lua_getfield(L, -1, "new"); lua_pcall(L,0,1,0); lua_newtable(L); lua_setglobal(L, "objname");

Lua C API-从C++; 我尝试实例化并使用C++中的Lua类对象。 Lua类的定义如下 myclass = {} function myclass:new(o) o=o or {} setmetatable(o,self) self.__index=self return o end function myclass:init() self.something = 0 end function myclass:perform() self.something = self.something + 0.5 return performsomething(self.something) end 在C++中实例化对象,我做以下操作: lua_getglobal(L,"myclass"); lua_getfield(L, -1, "new"); lua_pcall(L,0,1,0); lua_newtable(L); lua_setglobal(L, "objname");,c++,lua,lua-api,C++,Lua,Lua Api,然后初始化: lua_getglobal(L,"myclass"); lua_getfield(L, -1, "init"); lua_getglobal(L,"objname"); lua_pcall(L, 0, 0, 0); 然后执行: lua_getglobal(L, "myclass"); lua_getfield(L, -1, "perform"); lua_getglobal(L, "objname"); lua_pcall(L, 0, 1, 0); double res = lu

然后初始化:

lua_getglobal(L,"myclass");
lua_getfield(L, -1, "init");
lua_getglobal(L,"objname");
lua_pcall(L, 0, 0, 0);
然后执行:

lua_getglobal(L, "myclass");
lua_getfield(L, -1, "perform");
lua_getglobal(L, "objname");
lua_pcall(L, 0, 1, 0);
double res = lua_tonumber(-1);
对于这个例子,我没有包括在需要时使用的
lua\u pop()
方法

看来,通过指纹,我可以得到以下信息。已使用新方法成功实例化Lua对象。它也在init方法中成功初始化。但是,当调用perform方法时,
self.something
member没有改变,它的值被设置为0,这似乎意味着我没有调用对象成员方法。
我很确定我管理Lua堆栈以访问对象成员函数的方式有问题

是否有人已经处理过类似的案例,并且可以在这里提供帮助? 谢谢
Bests

很可能您没有将
nargs
参数修改为
lua\u pcall
函数

使用冒号语法(
class:func()
)定义函数时,必须从C/C++端显式传递
self
参数。在你的例子中没有这样的例子

只需对代码进行最低限度的更改,它将如下所示:

卢阿方面:

function performsomething(x)
    print("type:", type(x))
    print("value:", x)
    return x
end

myclass = {}

function myclass:new(o)
   o=o or {}
   setmetatable(o,self)
   self.__index=self
   return o
end

function myclass:init()
   self.something = 0
end

function myclass:perform()
   self.something = self.something + 0.5
   return performsomething(self.something)
end
C/C++端:

#include <stdio.h>
#include <lualib.h>
#include <lauxlib.h>

int main()
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    luaL_dofile(L, "myclass.lua");

    // instantiate
    lua_getglobal(L,"myclass");
    lua_getfield(L, -1, "new");
    lua_getglobal(L, "myclass");
    lua_pcall(L,1,1,0);
    lua_setglobal(L, "objname");

    // init
    lua_getglobal(L,"myclass");
    lua_getfield(L, -1, "init");
    lua_getglobal(L,"objname");
    lua_pcall(L, 1, 0, 0);

    // perform
    lua_getglobal(L, "myclass");
    lua_getfield(L, -1, "perform");
    lua_getglobal(L, "objname");
    lua_pcall(L, 1, 1, 0);

    double res = lua_tonumber(L, -1);
    printf("Result: %f\n", res);

    lua_close(L);

    return 0;
}
#包括
#包括
#包括
int main()
{
lua_State*L=luaL_newstate();
luaL_openlibs(L);
luaL_dofile(L,“myclass.lua”);
//实例化
lua_getglobal(L,“myclass”);
卢厄·格特菲尔德(L,-1,“新”);
lua_getglobal(L,“myclass”);
lua_pcall(L,1,1,0);
lua_setglobal(L,“objname”);
//初始化
lua_getglobal(L,“myclass”);
lua_getfield(L,-1,“init”);
lua_getglobal(L,“objname”);
lua_pcall(L,1,0,0);
//表演
lua_getglobal(L,“myclass”);
lua_getfield(L,-1,“执行”);
lua_getglobal(L,“objname”);
lua_pcall(L,1,1,0);
双精度=对数(L,-1);
printf(“结果:%f\n”,res);
卢厄关闭(L);
返回0;
}

很可能您没有将
nargs
参数修改为
lua\u pcall
函数

使用冒号语法(
class:func()
)定义函数时,必须从C/C++端显式传递
self
参数。在你的例子中没有这样的例子

只需对代码进行最低限度的更改,它将如下所示:

卢阿方面:

function performsomething(x)
    print("type:", type(x))
    print("value:", x)
    return x
end

myclass = {}

function myclass:new(o)
   o=o or {}
   setmetatable(o,self)
   self.__index=self
   return o
end

function myclass:init()
   self.something = 0
end

function myclass:perform()
   self.something = self.something + 0.5
   return performsomething(self.something)
end
C/C++端:

#include <stdio.h>
#include <lualib.h>
#include <lauxlib.h>

int main()
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    luaL_dofile(L, "myclass.lua");

    // instantiate
    lua_getglobal(L,"myclass");
    lua_getfield(L, -1, "new");
    lua_getglobal(L, "myclass");
    lua_pcall(L,1,1,0);
    lua_setglobal(L, "objname");

    // init
    lua_getglobal(L,"myclass");
    lua_getfield(L, -1, "init");
    lua_getglobal(L,"objname");
    lua_pcall(L, 1, 0, 0);

    // perform
    lua_getglobal(L, "myclass");
    lua_getfield(L, -1, "perform");
    lua_getglobal(L, "objname");
    lua_pcall(L, 1, 1, 0);

    double res = lua_tonumber(L, -1);
    printf("Result: %f\n", res);

    lua_close(L);

    return 0;
}
#包括
#包括
#包括
int main()
{
lua_State*L=luaL_newstate();
luaL_openlibs(L);
luaL_dofile(L,“myclass.lua”);
//实例化
lua_getglobal(L,“myclass”);
卢厄·格特菲尔德(L,-1,“新”);
lua_getglobal(L,“myclass”);
lua_pcall(L,1,1,0);
lua_setglobal(L,“objname”);
//初始化
lua_getglobal(L,“myclass”);
lua_getfield(L,-1,“init”);
lua_getglobal(L,“objname”);
lua_pcall(L,1,0,0);
//表演
lua_getglobal(L,“myclass”);
lua_getfield(L,-1,“执行”);
lua_getglobal(L,“objname”);
lua_pcall(L,1,1,0);
双精度=对数(L,-1);
printf(“结果:%f\n”,res);
卢厄关闭(L);
返回0;
}

在下面的例子中,我创建了C++中的一个简单类,可以使用LuaCAPI在Lua中使用。完成后,我想大部分内容超出了你的问题范围;不过,我希望我的解释和例子能有所帮助

<>当我使用Lua的C API创建<代码> USEDATABAS/COD>时,这就是我通常在C++中编写我的<代码>主< /C>函数的方法。在本例中,
MyClass.h
是我为本例编写的简单类的头文件

#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include "MyClass.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

int main(int argc, char** argv) {
    // Check to make sure you have at least one .lua input file.
    if (argc < 2) {
        std::cerr << "Filename(s) expected from command line" << std::endl;
        std::exit(EXIT_FAILURE);
    }

    // Try-catch block to handle any errors encountered when executing the Lua file(s).
    try {
        lua_State* L = luaL_newstate(L);
        luaL_openlibs(L);
        // Call a function to register Lua methods for `MyClass`; its declaration and definition are below.
        lua_MyClass_register(L);
        for (char** cpp = argv + 1; cpp < argv + argc; ++cpp) {
            // Run the Lua script--provided as a command-line arg--and handle errors.
            if (luaL_dofile(L, *cpp)) {
                const char* err = lua_tostring(L, -1);
                lua_close(L);
                throw std::runtime_error(err);
            }
        }
        lua_close(L);
    } catch (const std::runtime_error &err) {
        // Catch fatal errors from the Lua script and exit.
        std::cerr << err.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return 0;
}
下面是
MyClass.h
对应的
.cpp
文件:

#include "MyClass.h"

// These are the class member function definitions.
MyClass::MyClass(int something_in) {
    something = something_in;
}

MyClass::~MyClass() {

}

void MyClass::set(int something_in) {
    something = something_in;
    return;
}

const int & MyClass::get() const {
    return something;
}

// These are the definitions for the C functions that Lua will use to call the member functions.
// `MyClass` constructor, which corresponds to `MyClass.new` in Lua.
int lua_MyClass_new(lua_State* L) {
    // Optional argument to supply to the `MyClass` constructor; using `luaL_optinteger`, it defaults to 0.
    int something_in = static_cast<int>(luaL_optinteger(L, 1, 0));
    MyClass** mcpp = reinterpret_cast<MyClass**>(lua_newuserdata(L, sizeof(MyClass**)));
    *mcpp = new MyClass(something_in);
    luaL_setmetatable(L, LUA_MYCLASS);
    return 1;
}

// `MyClass` destructor, which corresponds to the `__gc` metamethod in Lua.
int lua_MyClass_delete(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    delete mcp;
    return 0;
}

// C function corresponding to `MyClass::set`.
int lua_MyClass_set(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    int something_in = static_cast<int>(luaL_checkinteger(L, 2));
    mcp->set(something_in);
    return 0;
}

// C function corresponding to `MyClass::get`.
int lua_MyClass_get(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    lua_pushinteger(L, mcp->get());
    return 1;
}

// `__newindex` metamethod for `MyClass` userdata that prevents any members from being added.
int lua_MyClass_newindex(lua_State* L) {
    return luaL_error(L, "attempt to modify a read-only object");
}

// `__newindex` metamethod for the `MyClass` table that prevents any methods from being added--I will explain more below.
int lua_MyClass_table_newindex(lua_State* L) {
    return luaL_error(L, "attempt to modify a read-only table");
}

// Function to register all the above functions for use in Lua; this gets called in `main.cpp`.
void lua_MyClass_register(lua_State* L) {
    // Create a global table that will contain all the `MyClass` methods as functions.
    // Include `lua_MyClass_new` as a constructor in the form `MyClass.new`.
    lua_newtable(L);
    lua_pushcfunction(L, lua_MyClass_new);
    lua_setfield(L, -2, "new");
    // Include `MyClass::get` and `MyClass::set` in this table as well.
    luaL_setfuncs(L, MyClass_methods, 0);

    // Create a metatable for the global table `MyClass`--which was just created.
    lua_newtable(L);
    // Prevent access to the metatable.
    lua_pushliteral(L, "metatable");
    lua_setfield(L, -2, "__metatable");
    lua_pushcfunction(L, lua_MyClass_table_newindex);
    lua_setfield(L, -2, "__newindex");
    // Set this second table as the metatable for the one created above.
    lua_setmetatable(L, -2);
    // Call the first table "MyClass" and add it to the global environment table (_ENV).
    lua_setglobal(L, LUA_MYCLASS);

    // Create a metatable to be used by `MyClass` objects--this is different from the above tables because it will not contain the `new` method.
    luaL_newmetatable(L, LUA_MYCLASS);
    // Same as before, lock the metatable.
    lua_pushliteral(L, "metatable");
    lua_setfield(L, -2, "__metatable");
    // Add metamethods contained in the `luaL_Reg` struct `MyClass_metamethods`.
    luaL_setfuncs(L, MyClass_metamethods, 0);

    // Create an index--the `__index` metamethod--for the above table to use for `MyClass` objects.
    lua_newtable(L);
    // Add methods.
    luaL_setfuncs(L, MyClass_methods, 0);
    lua_setfield(L, -2, "__index");
    // This pop operation is probably unnecessary since the Lua stack should be cleaned up when this function returns.
    lua_pop(L, 1);

    return;
}
这将输出以下内容:

0
5
6

函数
lua_MyClass_register
的定义非常复杂,需要创建许多表。我这样写是因为我想创建一个全局表,其中包含
MyClass
构造函数和方法,其形式与Lua中的全局
string
表相同。以函数
string.match
为例:它可以作为函数调用,就像
string.match(str,pattern)
一样;或者,它可以作为方法调用,如
str:match(pattern)
。我注册了<代码> MyClass < /COD>所有函数的方式允许这种行为,除了全局表<代码> MyClass < /C>还包含构造函数,而类型< >代码> MyClass < /C>不。

< P>在下面的示例中,我创建了C++中的一个简单类,可以使用LuaCAPI在Lua中使用。完成后,我想大部分内容超出了你的问题范围;不过,我希望我的解释和例子能有所帮助

<>当我使用Lua的C API创建<代码> USEDATABAS/COD>时,这就是我通常在C++中编写我的<代码>主< /C>函数的方法。在本例中,
MyClass.h
是我为本例编写的简单类的头文件

#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include "MyClass.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

int main(int argc, char** argv) {
    // Check to make sure you have at least one .lua input file.
    if (argc < 2) {
        std::cerr << "Filename(s) expected from command line" << std::endl;
        std::exit(EXIT_FAILURE);
    }

    // Try-catch block to handle any errors encountered when executing the Lua file(s).
    try {
        lua_State* L = luaL_newstate(L);
        luaL_openlibs(L);
        // Call a function to register Lua methods for `MyClass`; its declaration and definition are below.
        lua_MyClass_register(L);
        for (char** cpp = argv + 1; cpp < argv + argc; ++cpp) {
            // Run the Lua script--provided as a command-line arg--and handle errors.
            if (luaL_dofile(L, *cpp)) {
                const char* err = lua_tostring(L, -1);
                lua_close(L);
                throw std::runtime_error(err);
            }
        }
        lua_close(L);
    } catch (const std::runtime_error &err) {
        // Catch fatal errors from the Lua script and exit.
        std::cerr << err.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return 0;
}
下面是
MyClass.h
对应的
.cpp
文件:

#include "MyClass.h"

// These are the class member function definitions.
MyClass::MyClass(int something_in) {
    something = something_in;
}

MyClass::~MyClass() {

}

void MyClass::set(int something_in) {
    something = something_in;
    return;
}

const int & MyClass::get() const {
    return something;
}

// These are the definitions for the C functions that Lua will use to call the member functions.
// `MyClass` constructor, which corresponds to `MyClass.new` in Lua.
int lua_MyClass_new(lua_State* L) {
    // Optional argument to supply to the `MyClass` constructor; using `luaL_optinteger`, it defaults to 0.
    int something_in = static_cast<int>(luaL_optinteger(L, 1, 0));
    MyClass** mcpp = reinterpret_cast<MyClass**>(lua_newuserdata(L, sizeof(MyClass**)));
    *mcpp = new MyClass(something_in);
    luaL_setmetatable(L, LUA_MYCLASS);
    return 1;
}

// `MyClass` destructor, which corresponds to the `__gc` metamethod in Lua.
int lua_MyClass_delete(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    delete mcp;
    return 0;
}

// C function corresponding to `MyClass::set`.
int lua_MyClass_set(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    int something_in = static_cast<int>(luaL_checkinteger(L, 2));
    mcp->set(something_in);
    return 0;
}

// C function corresponding to `MyClass::get`.
int lua_MyClass_get(lua_State* L) {
    MyClass* mcp = *reinterpret_cast<MyClass**>(luaL_checkudata(L, 1, LUA_MYCLASS));
    lua_pushinteger(L, mcp->get());
    return 1;
}

// `__newindex` metamethod for `MyClass` userdata that prevents any members from being added.
int lua_MyClass_newindex(lua_State* L) {
    return luaL_error(L, "attempt to modify a read-only object");
}

// `__newindex` metamethod for the `MyClass` table that prevents any methods from being added--I will explain more below.
int lua_MyClass_table_newindex(lua_State* L) {
    return luaL_error(L, "attempt to modify a read-only table");
}

// Function to register all the above functions for use in Lua; this gets called in `main.cpp`.
void lua_MyClass_register(lua_State* L) {
    // Create a global table that will contain all the `MyClass` methods as functions.
    // Include `lua_MyClass_new` as a constructor in the form `MyClass.new`.
    lua_newtable(L);
    lua_pushcfunction(L, lua_MyClass_new);
    lua_setfield(L, -2, "new");
    // Include `MyClass::get` and `MyClass::set` in this table as well.
    luaL_setfuncs(L, MyClass_methods, 0);

    // Create a metatable for the global table `MyClass`--which was just created.
    lua_newtable(L);
    // Prevent access to the metatable.
    lua_pushliteral(L, "metatable");
    lua_setfield(L, -2, "__metatable");
    lua_pushcfunction(L, lua_MyClass_table_newindex);
    lua_setfield(L, -2, "__newindex");
    // Set this second table as the metatable for the one created above.
    lua_setmetatable(L, -2);
    // Call the first table "MyClass" and add it to the global environment table (_ENV).
    lua_setglobal(L, LUA_MYCLASS);

    // Create a metatable to be used by `MyClass` objects--this is different from the above tables because it will not contain the `new` method.
    luaL_newmetatable(L, LUA_MYCLASS);
    // Same as before, lock the metatable.
    lua_pushliteral(L, "metatable");
    lua_setfield(L, -2, "__metatable");
    // Add metamethods contained in the `luaL_Reg` struct `MyClass_metamethods`.
    luaL_setfuncs(L, MyClass_metamethods, 0);

    // Create an index--the `__index` metamethod--for the above table to use for `MyClass` objects.
    lua_newtable(L);
    // Add methods.
    luaL_setfuncs(L, MyClass_methods, 0);
    lua_setfield(L, -2, "__index");
    // This pop operation is probably unnecessary since the Lua stack should be cleaned up when this function returns.
    lua_pop(L, 1);

    return;
}
这将输出以下内容:

0
5
6

函数
lua_MyClass_register
的定义非常复杂,需要创建许多表。我这样写是因为我想创建一个全局表,其中包含
MyClass
构造函数和方法,其形式与Lua中的全局
string
表相同。以函数
string.match
为例:它可以作为函数调用,就像
string.match(str,pattern)
一样;或者,它可以作为方法调用,如
str:match(pattern)
。我为
MyClass
注册所有函数的方式允许这种行为,但全局表
MyClass
也包含构造函数,而
MyClass
类型的对象不包含构造函数。

我不确定该怎么做。对不起,我的第一条评论是错误的。