基类
local a = {}
function a:new(name)
local a_n = {}
setmetatable(a_n, self)
self.__index = self
self.name = name
print("a-----new ", "'a-address'---- ", a, "'a_n-address'---- ", a_n)
print("a_n getmetatable ",getmetatable(a_n))
return a_n
end
function a:printName()
print("a----- ", self.name)
end
子类
local b = {}
//正确写法 begin
local b = a:new({name = "", value = ""})
//正确写法 end
function b:new(name)
local b_n = a:new(name)
setmetatable(b_n, self)
self.__index = self
self.name_new = name
print("b-------new ", "'a-address'---- ", a, "'b-address'---- ", b, "'b_n-address'---- ", b_n)
print("b_n getmetatable ",getmetatable(b_n))
return b_n
end
function b:printAdd()
print("b----printAdd", self.name_new)
end
实例化
local b_1 = b:new("name_b")
print("'b_1-adress'----- ", b_1)
b_1:printAdd()
b_1:printName()
运行结果
a-----new 'a-address'---- table: 0x126d0d0 'a_n-address'---- table: 0x126b980
a_n getmetatable table: 0x126d0d0
b-------new 'a-address'---- table: 0x126d0d0 'b-address'---- table: 0x126bea0 'b_n-address'---- table: 0x126b980
b_n getmetatable table: 0x126bea0
'b_1-adress'----- table: 0x126b980
b----printAdd name_b
lua: /usercode/file.lua:43: attempt to call method 'printName' (a nil value)
stack traceback:
/usercode/file.lua:43: in main chunk
[C]: in ?
错误原因
step1: b_1实际为b:new()中返回的b_n;
step2: b_1调用printName方法时,先去b_n中去找,可知,未找到;
step3: 检测b_n是否有元表,进而判断元表中是否有__index方法,若有,则去__index中找,由代码可知,b_n元表为b,b中有printAdd方法,故b_1:printAdd()这一句调用成功,b中无printName方法,故报错
思考一
由代码可知,a中包含printName方法,是否可以通过将b_n的元表设为a来解决问题,实验如下:
local b = {}
function b:new(name)
local b_n = a:new(name)
setmetatable(b_n, a)
self.__index = a
self.name_new = name
print("b-------new ", "'a-address'---- ", a, "'b-address'---- ", b, "'b_n-address'---- ", b_n)
print("b_n getmetatable ",getmetatable(b_n))
return b_n
end
function b:printAdd()
print("b----printAdd", self.name_new)
end
实例化
local b_1 = b:new("name_b")
print("'b_1-adress'----- ", b_1)
b_1:printName()
b_1:printAdd()
运行结果
a-----new 'a-address'---- table: 0x7a3070 'a_n-address'---- table: 0x7a3ca0
a_n getmetatable table: 0x7a3070
b-------new 'a-address'---- table: 0x7a3070 'b-address'---- table: 0x7a1ea0 'b_n-address'---- table: 0x7a3ca0
b_n getmetatable table: 0x7a3070
'b_1-adress'----- table: 0x7a3ca0
a----- name_b
lua: /usercode/file.lua:43: attempt to call method 'printAdd' (a nil value)
stack traceback:
/usercode/file.lua:43: in main chunk
[C]: in ?
结果分析
此时,b_1:printName()成功打印出a----- name_b,但是b_1:printAdd()报错,是因为此时b_n的元表不再是b,调用printAdd时,在b_n中找不到,去元表a中依然未找到,故报错。
继承的意义不光是子类保留父类的特征和行为,也包含子类可根据需要定制自身的特征和行为,以上结果,则只允许子类使用父类变量及函数,显然不符合设计的初衷;由此总结,当b定义为空表时,不可以通过改变b_n的元表来使得b_1可以访问a的方法;
思考二
不改变b的定义方式,将b_n定义为空表,其余不变,如下
local b = a:new("")
function b:new(name)
local b_n = {}
setmetatable(b_n, self)
self.__index = self
self.name_new = name
print(a.printName)
return b_n
end
实例化
local b_1 = b:new("name_b")
b_1:printName()
b_1:printAdd()
运行结果
b---------
b----printAdd name_b
结果分析
此时,b_1调用printName()时,打印的self.name为空值,是因为在b:new的时候,未给基类a中的变量赋值