这里主要说一下Lua在面向对象的使用中需要注意的地方。
一.self
self指的是调用者自身,例如:
local a = Shape:New(nil, 10),即local a = Shape.New(self, nil, 10),self指的是Shape;
a:PrintArea(),即a.PrintArea(self),self指的是a。
1 Shape = {area = 0} 2 3 function Shape:New(o, side) 4 o = o or {} 5 setmetatable(o, self) 6 self.__index = self 7 side = side or 0 8 self.area = side * side 9 return o 10 end 11 12 function Shape:PrintArea() 13 print("面积为 ", self.area) 14 end 15 16 print(Shape.area) 17 18 local a = Shape:New(nil, 10) 19 a:PrintArea() 20 print(Shape.area) 21 22 local b = Shape:New(nil, 20) 23 b:PrintArea() 24 print(Shape.area) 25 26 a:PrintArea() 27 print(Shape.area)
输出分析:
第二句,在Shape:New(nil, 10)时,Shape.area被赋值为100,在a:PrintArea()时,本来要打印的是a.area,但该键值为空,实际打印的是Shape.area。
第六句,在Shape:New(nil, 20)时,Shape.area被赋值为400。
那么,可以将上面的self.area = side * side改一下,改为o.area = side * side,输出如下。可以看到,此时New出来的实例都有各自的area值,不影响Shape表,此时才是符合面向对象设计的。
二.元表的__index元方法
__index元方法是用来查找值的,因此可以认为是“可读不可写”的。当查找到表中的某键的值为nil时,就会访问元表的__index元方法。
如下输出所示,可以发现:
1.像a.xxx这种,都是直接对a表进行赋值,不影响Shape表;而a.testTb[2]这种非直接赋值,会影响Shape表
1 Shape = {area = 0, test = 123, testTb = {"q","w"}} 2 3 function Shape:New(o, side) 4 o = o or {} 5 setmetatable(o, self) 6 self.__index = self 7 side = side or 0 8 --self.area = side * side 9 o.area = side * side 10 return o 11 end 12 13 function Shape:PrintArea() 14 print("面积为 ", self.area) 15 end 16 17 local a = Shape:New(nil, 10) 18 print(a.test) 19 print(a.test2) 20 print(Shape.test) 21 22 print("------------------------") 23 a.test = 456 24 print(a.test) 25 print(Shape.test) 26 27 print("------------------------") 28 Shape.test = 789 29 print(a.test) 30 print(Shape.test) 31 32 print("------------------------1") 33 print(a.testTb[2]) 34 a.testTb[2] = "z" 35 36 print("------------------------2") 37 a.testTb = nil 38 for i=1,#a.testTb do 39 print(a.testTb[i]) 40 end 41 print("------------------------3") 42 for i=1,#Shape.testTb do 43 print(Shape.testTb[i]) 44 end 45 46 print("------------------------4") 47 a.testTb = {} 48 for i=1,#a.testTb do 49 print(a.testTb[i]) 50 end 51 print("------------------------5") 52 for i=1,#Shape.testTb do 53 print(Shape.testTb[i]) 54 end
三.默认值
1.使用元表设置默认值,这种方法的好处是修改元表后,会修改所有子表的默认值。
1 Shape = {area = 0, test = 123} 2 3 function Shape:New(o, side) 4 o = o or {} 5 setmetatable(o, self) 6 self.__index = self 7 side = side or 0 8 --self.area = side * side 9 o.area = side * side 10 return o 11 end 12 13 function Shape:PrintArea() 14 print("面积为 ", self.area) 15 end 16 17 local a = Shape:New(nil, 10) 18 local b = Shape:New(nil, 10) 19 print(a.test) 20 print(b.test) 21 print(Shape.test) 22 Shape.test = 456 23 print(a.test) 24 print(b.test)
2.使用New设置默认值,这种方法会使每张表有各自的值,修改元表不会对其进行影响。
1 Shape = {area = 0, test = 123} 2 3 function Shape:New(o, side) 4 o = o or {} 5 setmetatable(o, self) 6 self.__index = self 7 side = side or 0 8 --self.area = side * side 9 o.area = side * side 10 o.test = 789 11 return o 12 end 13 14 function Shape:PrintArea() 15 print("面积为 ", self.area) 16 end 17 18 local a = Shape:New(nil, 10) 19 local b = Shape:New(nil, 10) 20 print(a.test) 21 print(b.test) 22 print(Shape.test) 23 Shape.test = 456 24 a.test = 111 25 print(a.test) 26 print(b.test)
四.调用父类方法
1 Shape = {} 2 3 function Shape:New(o, side) 4 o = o or {} 5 setmetatable(o, self) 6 self.__index = self 7 side = side or 0 8 o.area = side * side 9 return o 10 end 11 12 function Shape:PrintArea() 13 print("Shape面积为 ", self.area) 14 end 15 16 Square = Shape:New() 17 18 function Square:New(o, side) 19 o = o or {} 20 setmetatable(o, self) 21 self.__index = self 22 side = side or 0 23 o.area = side * side 24 return o 25 end 26 27 function Square:PrintArea() 28 print("Square面积为 ", self.area) 29 Shape.PrintArea(self) 30 end 31 32 local a = Shape:New(nil, 10) 33 local b = Square:New(nil, 20) 34 print(a:PrintArea()) 35 print("-------------") 36 print(b:PrintArea())
五.继承中的table问题
1 A = {} 2 3 function A:New() 4 local o = {} 5 setmetatable(o, self) 6 self.__index = self 7 o.child = {} 8 return o 9 end 10 11 function A:AddChild() 12 table.insert(self.child, 1) 13 end 14 15 function A:Print() 16 print(#self.child) 17 end 18 19 B = A:New() 20 21 function B:New() 22 local o = {} 23 setmetatable(o, self) 24 self.__index = self 25 return o 26 end 27 28 local b1 = B:New(); 29 local b2 = B:New(); 30 b1:AddChild() 31 b1:Print() 32 b2:Print() 33 b2:AddChild() 34 b2:Print()
如上,b1和b2共用A表中的child,而正确来说b1和b2要有各自的child,因此在B:New()中添加语句:o.child = {},输出如下: