3

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

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

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

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

  • Player 类将仅覆盖getDescription ()方法。
  • Player 类也将继承 Creature 的 getName () 方法。
  • Player 的getDescription()返回一个字符串:“ This is a player ”。

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

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

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

应该打印:

这是一个生物
Bob
这是一个玩家
Joey

基本上,我的问题是 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
4

1 回答 1

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

对于最后一个问题,您只需在派生类中为其分配一个新函数即可覆盖现有方法。例如。所以要覆盖你可以这样做getDescriptionPlayer

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库已经实现了一个类似于我上面描述的类系统,但功能和完整得多。除非这是一个练习,否则请考虑使用它而不是重新发明另一个 lua OOP 系统。

于 2015-01-05T06:16:59.887 回答