Lua 中的子 class 构造函数方法

Child class constructor method in Lua

在 Lua 中理解继承(和元表)的概念有点困难。官方教程没有具体说明如何为子class.

构造构造函数

我的例子的问题是 player:move()nil,所以玩家仍然是 Object class

-- Generic class
Object = {}
function Object:new (type,id,name)
    o = {}
    self.type = type or "none"
    self.id = id or 0
    self.name = name or "noname"
    setmetatable(o, self)
    self.__index = self
    return o
end

function Object:place(x,y)
    self.x = x
    self.y = y
end

-- Player class
Player = Object:new()

function Player:new(id,name)
    o = Object:new("player",id,name)
    o.inventory = {}
    o.collisions = {}
    return o
end

function Player:move(x,y)
    return print("moved to " ..x.." x " .. y)
end

local player = Player:new(1, "plyr1")
player:move(2,2)

在构造函数 Player:new 中,我们通过以下行返回 Object class 的对象:

o = Object:new("player",id,name)

一旦我们删除它,player:move() 将被调用:

moved to 2 x 2

原因是,即使我们正在调用 Player:new 构造函数,我们实际上在其中返回了 Object class 的一个实例。在这种情况下,o 继承了 属性。

classes 继承示例

通用 class

Object = {}

function Object:__tostring()
   if rawget(self, "type") then  -- only classes have field "type"
      return "Class: "..tostring(self.type)
   else                          -- instances of classes do not have field "type"
      return 
         "Type: "..tostring(self.type)..", id: "..tostring(self.id)
         ..", name: "..tostring(self.name)
   end
end

function Object:newChildClass(type)  -- constructor of subclass
   self.__index = self
   return
      setmetatable({
         type = type or "none",
         parentClass = self,
         __tostring = self.__tostring
      }, self)
end

function Object:new(id, name)        -- constructor of instance
   self.__index = self
   return
      setmetatable({
         id = id or 0,
         name = name or "noname"
      }, self)
end

function Object:place(x,y)
   self.x = x
   self.y = y
end

玩家class

Player = Object:newChildClass("player")

function Player:new(id,name)
  local o = Player.parentClass.new(self, id, name)  -- call inherited constructor
  o.inventory = {}
  o.collisions = {}
  return o
end

function Player:move(x, y)
   self:place(x, y)
   print("moved to (" ..self.x..", " .. self.y..")")
end

local player = Player:new(1, "plyr1")
print(player)     -->  Type: player, id: 1, name: plyr1
player:move(2,2)  -->  moved to (2, 2)

如何创建子class并调用继承的方法

Dog = Player:newChildClass("dog")

--- we want to override method "move" in class "dog"
function Dog:move(x, y)
   Dog.parentClass.move(self, x, y)  -- call inherited method "move"
   print("Woof!")   -- dog says "woof" after every move
end

local dog = Dog:new(42, "dg42")
print(dog)       -->  Type: dog, id: 42, name: dg42
dog:move(3,4)    -->  moved to (3, 4)
                 -->  Woof!