继承metatable(类)并使用其必需的构造函数参数

时间:2015-01-04 21:32:46

标签: lua metatable

我找到了这个教程:http://lua-users.org/wiki/InheritanceTutorial

我有一个叫做生物的元词。 Creature在其构造函数中需要一个参数。 必需参数是表示名称的字符串。

local creature = Creature(name)
  • Creature有很多其他方法,例如getDescription()
  • Creature的getDescription ()返回一个字符串:“这是一个生物”。
  • Creature的getName ()返回一个字符串:名称

我想创建一个名为Player的新metatable(类)并让它继承Creature metatable(class)

  • Player类将仅覆盖 getDescription()方法。
  • Player类还将继承Creature的getName()方法。
  • 播放器的 getDescription()返回一个字符串:“这是一个播放器”。

我希望能够做到以下几点:

local creature = Creature("Bob")
print(creature:getDescription())
print(creature:getName())

local player = Player("Joey")
print(player:getDescription())
print(player:getName())

应打印:

  

这是一个生物
  鲍勃
  这是一名球员   乔伊

基本上,我的问题是Creature类需要一个参数来识别某人,一个名字。它的getName ()函数使用参数中的值并打印它。如果我要使用Player继承Creature的所有功能(并在必要时覆盖),我如何更改代码以确保Player获得所需的参数?

从教程中获取的代码:

-- Create a new class that inherits from a base class
--
function inheritsFrom( baseClass )

    -- The following lines are equivalent to the SimpleClass example:

    -- Create the table and metatable representing the class.
    local new_class = {}
    local class_mt = { __index = new_class }

    -- Note that this function uses class_mt as an upvalue, so every instance
    -- of the class will share the same metatable.
    --
    function new_class:create()
        local newinst = {}
        setmetatable( newinst, class_mt )
        return newinst
    end

    -- The following is the key to implementing inheritance:

    -- The __index member of the new class's metatable references the
    -- base class.  This implies that all methods of the base class will
    -- be exposed to the sub-class, and that the sub-class can override
    -- any of these methods.
    --
    if baseClass then
        setmetatable( new_class, { __index = baseClass } )
    end

    return new_class
end

1 个答案:

答案 0 :(得分:3)

  

我希望能够做到以下几点:

local creature = Creature("Bob")
print(creature:getDescription())
print(creature:getName())
-- ...

在lua中支持这种类使用语法肯定是可能的 - 这只是一个如何使用语言机制和工具来实现这一点的问题。要决定的一些重要问题:

  • 对象构建将如何发生?该类应该调用什么函数来初始化实例?
  • 客户端代码的对象实例化是什么样的?
  • 如何完成方法覆盖?

在wiki教程中,new_class:create()创建了一个新实例,但没有调用任何构造函数。因此,在您的OOP系统中,您必须决定客户端代码提供的类似构造函数的函数,并且类创建将调用。例如:

function new_class:create(...)
    local instance = setmetatable( {}, class_mt )
    if new_class.__init__ then new_class.__init__(instance, ...) end
    return instance
end

这里我只使用__init__作为构造函数名称,类似于python,但实际上只要使用代码和类创建代码同意,任何名称都可以使用。

为了支持Creature("Bob")Player("Joey")等对象创建语法,您可以使它们成为实际的函数调用,也可以使用__call元方法。使用后者是对__call的简单分配:

function inheritsFrom( baseClass )
  local new_class = setmetatable( {}, { __index = baseClass } )
  -- ...
  getmetatable(new_class).__call = new_class.create
  return new_class
end

对于最后一个问题,您只需在派生类中为其指定一个新函数,即可覆盖现有方法。例如。因此,要覆盖getDescription中的Player,您可以执行以下操作:

function Player:getDescription()
    return "Is a player"
end

将所有内容放在一起,inheritsFrom

function inheritsFrom( baseClass )
    local new_class = setmetatable( {}, { __index = baseClass } )

    local class_mt = { __index = new_class }
    function new_class:create(...)
        local instance = setmetatable( {}, class_mt )
        if new_class.__init__ then new_class.__init__(instance, ...) end
        return instance
    end

    getmetatable(new_class).__call = new_class.create
    return new_class
end

定义班级Creature +一个生物实例:

local Creature = inheritsFrom
{
  __init__ = function(self, name) self.name = name end;
  getDescription = function(self) return "Is a creature" end;
  getName = function(self) return self.name end;
}

local bob = Creature "Bob"
print(bob:getDescription())
print(bob:getName())

PlayerCreature进行子类化并覆盖getDescription

local Player = inheritsFrom(Creature)
function Player:getDescription()
    return "Is a player"
end

local joey = Player "Joey"
print(joey:getDescription())
print(joey:getName())

作为最后的评论,lua Penlight库已经实现了类似于我上面描述的class system,但更加功能和完整。除非这是一个练习,否则请考虑使用它而不是重新发明另一个lua OOP系统。