【问题标题】:How to implement inheritance for Lua classes whose __index is a function?如何为__index是函数的Lua类实现继承?
【发布时间】:2021-09-23 05:14:42
【问题描述】:

通过this tutorial,Lua 可以通过将元表分配给其__index 指向基类表的派生类表来实现继承,如下所示:

BaseClass = {}
function BaseClass:foo()
end

DerivedClass = {}
setmetatable(DerivedClass, {__index=BaseClass}) -- set inheritance here

derived_instance = {}
setmetatable(derived_instance, {__index=DerivedClass})
derived_instance:foo() -- derived_instance can call BaseClass method foo()

然而,Lua 中的面向对象也可以通过元表__index 指向一个函数来实现。这提供了更好的灵活性,但我不知道如何实现继承。此测试代码演示了我的想法,但无法运行:

#include <juce_core/juce_core.h>
#include <lauxlib.h>
#include <lualib.h>

int BaseClass_foo( lua_State* lua )
{
    juce::Logger::writeToLog( "BaseClass_foo called" );
    return 0;
}

int BaseClass( lua_State* lua )
{
    juce::Logger::writeToLog( "BaseClass called" );
    const char* key = lua_tostring( lua, 2 );
    if ( strcmp( key, "foo" ) == 0 )
        lua_pushcfunction( lua, BaseClass_foo );
    else
        lua_pushnil( lua );
    return 1;
}

int DerivedClass( lua_State* lua )
{
    juce::Logger::writeToLog( "DerivedClass called" );
    lua_pushnil( lua );
    return 1;
}

const char* lua_src =
    "obj={}\n"
    "setmetatable(obj, {__index=DerivedClass})\n"
    "obj:foo()";

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

    lua_pushcfunction( lua, BaseClass );
    lua_setglobal( lua, "BaseClass" );
    lua_pushcfunction( lua, DerivedClass );
    lua_setglobal( lua, "DerivedClass" );

    // set inheritance by metatable on class function
    lua_getglobal( lua, "DerivedClass" );

    lua_createtable( lua, 0, 0 );
    lua_pushstring( lua, "__index" );
    lua_getglobal( lua, "BaseClass" );
    lua_settable( lua, -3 );
    
    lua_setmetatable( lua, -2 );

    // run lua code
    int load_re = luaL_loadstring( lua, lua_src );
    if ( load_re == LUA_OK )
        lua_call( lua, 0, 0 );
    else
        juce::Logger::writeToLog( "Lua source load failed with " + juce::String( load_re ) + ": " + lua_tostring( lua, -1 ) );

    lua_close( lua );
}

结果,Lua 声明了一个错误,即您无法在 nil 值上调用 foo,根本没有调用 BaseClass 函数。元索引搜索链在这里被打破,不同于表实现的类系统,如果DerivedClass 表中不存在键,Lua 会自动搜索BaseClass 表。有什么办法让 Lua 继续解释绑定到 DerivedClass 的元表?

【问题讨论】:

    标签: c++ lua


    【解决方案1】:

    如果有人索引DerivedClass.foo,那么__index 函数必须返回BaseClass.foo

    如果 __index 是一个表,你基本上可以这样做:

    getmetatable(DerivedClass).__index:foo()
    

    归结为BaseClass:foo()

    如果 __index 是一个函数,你可以这样做:

    getmetatable(DerivedClass).__index(DerivedClass, "foo")()
    

    因此,您的 __index 函数必须返回 BaseClass.foo 以使关键参数“foo”具有相同的效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 2012-04-22
      • 2013-07-05
      • 2018-11-25
      • 1970-01-01
      • 2019-03-23
      相关资源
      最近更新 更多