Lua中的子类构造器方法

在Lua中理解继承(和元表)的概念有些困难。官方教程没有明确讲解如何为子类创建构造器。

我的示例的问题在于player:move()nil,所以player仍然是Object类。

-- 通用类
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 = 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("移动到 " ..x.." x " .. y)
end

local player = Player:new(1, "plyr1")
player:move(2,2)
点赞
用户2227834
用户2227834

在构造函数 Player:new 中,我们通过以下代码行返回一个 Object 类的对象:

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

一旦我们移除它,player:move() 就会被调用:

moved to 2 x 2

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

2016-10-12 17:56:49
用户1847592
用户1847592

在类继承中的示例

通用类

Object = {}

function Object:__tostring()
   if rawget(self, "type") then  -- 只有类有 "type" 字段
      return "Class: "..tostring(self.type)
   else                          -- 类的实例没有 "type" 字段
      return
         "Type: "..tostring(self.type)..", id: "..tostring(self.id)
         ..", name: "..tostring(self.name)
   end
end

function Object:newChildClass(type)  -- 子类的构造函数
   self.__index = self
   return
      setmetatable({
         type = type or "none",
         parentClass = self,
         __tostring = self.__tostring
      }, self)
end

function Object:new(id, name)        -- 实例的构造函数
   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

玩家类

Player = Object:newChildClass("player")

function Player:new(id,name)
  local o = Player.parentClass.new(self, id, name)  -- 调用继承的构造函数
  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)

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

Dog = Player:newChildClass("dog")

--- 我们想要覆盖类 "dog" 中的方法 "move"
function Dog:move(x, y)
   Dog.parentClass.move(self, x, y)  -- 调用继承的方法 "move"
   print("Woof!")   -- 狗每次移动后会叫 "Woof!"
end

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