Lua面向对象

创建类

在lua中类其实就是一个table,现在需要使用这个创建好的table去创建多个对象。这就需要使用元表和元方法。

TSprite = {
  x = 0,
  y = 0,
}
function TSprite:setPosition(x, y)
  self.x = x;
  self.y = y;
end

function TSprite:new()
  o = {}
  setmetatable(o, {__index = self});
  return o;
end

local who1 = TSprite:new();
local who2 = TSprite:new();
who1:setPosition(1, 2);
who2:setPosition(44, 6);
print("who1坐标(" .. who1.x .. "," .. who1.y .. ")");
print("who2坐标(" .. who2.x .. "," .. who2.y .. ")");

留意TSprite的new方法。在这个方法里,首先创建了一个空table,然后给这个空table设置一个元表,这个原表的__index方法就是TSprite本身,最后返回这个设置好的table。于是这个table就可以使用TSprite的所有字段和方法了。

解释元表

这里需要先解释一下元表,setmetatable(a, b);大概的意思就是讲b设置为a的元表,如果在a上找不到的字段和方法就去b里找。这里{__index = self}也是一个临时创建的表,__index魔术方法可以在找不到这个表的字段的情况下,去self中找,而在这个语境下self就是TSprite。说到这里,可能就会发现,这里创建了一个临时的表,而这个表是不需要被创建的。所以,可以使用一个技巧去掉这个临时表。

function TSprite:new()
  o = {}
  setmetatable(o, self);
  self.__index = self;
  return o;
end

实现继承

既然我们知道了对象就是一个table,那么我们就可以基于父类的table来创建子类的table,同时可以新增属性和方法。

local TSub = TSprite:new()

function TSub:new()
  o = {}
  setmetatable(o, self);
  self.__index = self;
  self.tag = "new attr"
  return o;
end

function TSub:setPosition(x, y)
  self.x = 100 * x
  self.y = 100 * y
end

tn = TSub:new()
print(tn.tag)

tn.setPosition(1,2)
print("tn坐标(" .. tn.x .. "," .. tn.y .. ")");

可以看到,我们不仅增加了子类的属性,而且覆写的父类的一个方法,将位置扩大了100倍。增加方法也是同理,这里不在写演示代码了。

lua的继承可以说还是很有意思的,跟以往学习过的任何一种语言都不尽相同,但是只要掌握了元表这一特性,再明白所有的对象都只是一个表,就基本能掌握lua的面向对象了。