第5章:面向对象
一、导读
1.1 本章学习目标
第5章讲解 Lua 的面向对象编程:类模拟、继承、多重继承。
本章核心学习目标:
- 掌握用 table 模拟类
- 理解继承的实现
- 掌握多重继承
1.2 为什么本章如此重要
Lua 没有内置的类系统,但可以用 table 和元表灵活地模拟。理解这种模拟方式是掌握 Lua 高级编程的关键。
1.3 核心问题引导
Lua 如何模拟类和对象?
self 参数是如何传递的?
如何实现单继承和多继承?
二、核心概念详解
2.1 类模拟
lua
-- 定义类
local Account = {}
Account.__index = Account
function Account:new(balance)
local obj = {balance = balance or 0}
setmetatable(obj, self)
return obj
end
function Account:deposit(amount)
self.balance = self.balance + amount
end
function Account:withdraw(amount)
if amount > self.balance then error("insufficient funds") end
self.balance = self.balance - amount
end
function Account:getBalance()
return self.balance
end
-- 使用
local acc = Account:new(100)
acc:deposit(50)
print(acc:getBalance()) -- 150
-- 冒号语法糖:
-- acc:deposit(50) 等价于 Account.deposit(acc, 50)2.2 继承
lua
-- 单继承
local SpecialAccount = Account:new()
function SpecialAccount:withdraw(amount)
if amount > self:getLimit() then
error("insufficient funds")
end
self.balance = self.balance - amount
end
function SpecialAccount:getLimit()
return self.balance * 2
end
-- 使用
local special = SpecialAccount:new(100)
special:withdraw(150) -- OK, limit is 200
print(special:getBalance()) -- -502.3 多重继承
lua
function createClass(...)
local c = {}
local parents = {...}
-- 在父类中搜索方法
setmetatable(c, {
__index = function(t, k)
for _, parent in ipairs(parents) do
local v = parent[k]
if v then return v end
end
end
})
c.__index = c
function c:new(o)
o = o or {}
setmetatable(o, c)
return o
end
return c
end
-- 使用
local Named = {}
function Named:getName() return self.name end
function Named:setName(n) self.name = n end
local Printable = {}
function Printable:print() print(tostring(self)) end
local NamedPrintable = createClass(Named, Printable)
function NamedPrintable:new(name)
local obj = Named.new(self)
obj:setName(name)
return obj
end
local obj = NamedPrintable:new("test")
print(obj:getName()) -- test三、实战案例
3.1 案例一:形状类层次
lua
-- 基类
local Shape = {}
Shape.__index = Shape
function Shape:new(color)
local obj = {color = color or "black"}
setmetatable(obj, self)
return obj
end
function Shape:area()
error("subclass must implement area()")
end
-- 圆形
local Circle = Shape:new()
function Circle:new(radius, color)
local obj = Shape.new(self, color)
obj.radius = radius
return obj
end
function Circle:area()
return math.pi * self.radius ^ 2
end
-- 矩形
local Rectangle = Shape:new()
function Rectangle:new(width, height, color)
local obj = Shape.new(self, color)
obj.width = width
obj.height = height
return obj
end
function Rectangle:area()
return self.width * self.height
end
-- 使用
local shapes = {
Circle:new(5, "red"),
Rectangle:new(3, 4, "blue"),
}
for _, shape in ipairs(shapes) do
print(string.format("%s shape: area = %.2f", shape.color, shape:area()))
end四、本章小结
Lua 用 table + 元表 模拟类
冒号语法 (:) 自动传递 self
继承通过设置 __index 元方法实现
五、思考与练习
为什么 Lua 不内置类系统?
如何实现接口的概念?