Lua 实现面向对象 踩坑

基类

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中的变量赋值

Lua是一种脚本语言,它支持面向对象编程。在Lua中,我们可以通过表(table)来实现面向对象编程。表可以被看作是一个对象,它可以存储任意类型的数据(包括函数),还可以作为其他表的元素。下面是使用Lua实现面向对象的一些基本步骤: 1. 创建一个表,它代表一个类 2. 在这个表中定义一个构造函数,用于创建该类的实例 3. 在这个表中定义其他成员函数和成员变量 4. 在这个表中定义一个元表,用于实现继承和多态 下面是一个简单的例子,展示了如何使用Lua实现一个名为Person的类: ```lua -- 创建一个Person类 Person = {} -- 定义Person的构造函数 function Person:new(name, age) local obj = {} obj.name = name obj.age = age setmetatable(obj, self) self.__index = self return obj end -- 定义Person的成员函数 function Person:sayHello() print("Hello, my name is " .. self.name .. ", I'm " .. self.age .. " years old.") end -- 创建一个Person对象 local person = Person:new("Tom", 20) -- 调用对象的成员函数 person:sayHello() ``` 在这个例子中,我们首先创建了一个空表Person,它代表一个类。然后我们定义了Person的构造函数new,用于创建Person的实例。在构造函数中,我们创建了一个新表obj,并将name和age属性赋值给它。然后我们使用setmetatable函数将obj的元表设置为Person,并将self设置为__index。这样做可以让obj继承Person的成员函数。最后,我们返回obj。 接下来,我们定义了Person的成员函数sayHello,它用于打印出人的姓名和年龄。在最后,我们创建了一个Person对象person,并调用它的成员函数sayHello。 如果你想要继承Person类,你可以创建一个新的表Student,并将它的元表设置为Person。这样做可以让Student继承Person的成员函数和属性。如果你想要重写某个成员函数或属性,你可以直接在Student表中重新定义它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值