5Programming in Lua(第4版)

面向对象

Lua的OOP

类模拟继承多重继承元方法

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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())  -- -50

2.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 不内置类系统?

如何实现接口的概念?


5/8面向对象
0%