继承一个元表(类),并使用其所需的构造函数参数。

我发现这个教程: http://lua-users.org/wiki/InheritanceTutorial

我有一个叫做Creature的元表。Creature需要一个参数作为它的构造函数。

必需的参数是一个代表名称的字符串。

local creature = Creature(name)
  • Creature有很多其他方法,如getDescription()
  • Creature的getDescription()返回一个字符串:“_This is a creature_”。
  • Creature的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())

应该打印:

这是一个生物

鲍勃

这是一名球员

琼尼

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

从教程中拍摄的代码:

- 从基本类创建一个新类

--
function inheritsFrom( baseClass )

    --以下行与SimpleClass示例相同:

    --创建表示类的表和元表。
    local new_class = {}
    local class_mt = { __index = new_class }

    --请注意,此函数使用class_mt作为upvalue,因此类的每个实例
    --将共享相同的元表。
    --
    function new_class:create()
        local newinst = {}
        setmetatable( newinst, class_mt )
        return newinst
    end

    --以下是实现继承的关键:

    --新类的元表中的__index成员引用
    --基类。这意味着基类的所有方法将
    --暴露给子类,并且子类可以覆盖
    --其中的任何一个方法。
    --
    if baseClass then
        setmetatable( new_class, { __index = baseClass } )
    end

    return new_class
end
点赞
用户234175
用户234175

我想要实现以下功能:

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

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

  • 对象的构建是如何发生的?类应该调用哪个函数来初始化实例?
  • 客户端代码可以看到什么样子的对象实例?
  • 如何执行方法重载?

从维基教程中可以看到new_class:create()创建了一个新实例但不会调用任何 构造 函数。因此,在您的面向对象编程系统中,您需要决定客户端代码提供的 构造函数式 函数,类创建将调用该函数。例如:

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

对于最后一个问题,您只需在派生类中为该方法分配一个新函数即可覆盖现有方法。例如,要在 Player 中重载 getDescription,可以这样做:

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())

Creature中创建一个子类Player并重载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 面向对象编程系统。

2015-01-05 06:16:59