16.2 继承

通常面向对象语言中,继承使得类可以访问其他类的方法,这在Lua中也很容易现实:

假定我们有一个基类Account

Account = {balance = 0}

 

function Account:new (o)

    o = o or {}

    setmetatable(o, self)

    self.__index = self

    return o

end

 

function Account:deposit (v)

    self.balance = self.balance + v

end

 

function Account:withdraw (v)

    if v > self.balance then error"insufficient funds" end

    self.balance = self.balance - v

end

我们打算从基类派生出一个子类SpecialAccount,这个子类允许客户取款超过它的存款余额限制,我们从一个空类开始,从基类继承所有操作:

SpecialAccount = Account:new()

到现在为止,SpecialAccount仅仅是Account的一个实例。现在奇妙的事情发生了:

s = SpecialAccount:new{limit=1000.00}

SpecialAccountAccount继承了new方法,当new执行的时候,self参数指向SpecialAccount。所以,smetatableSpecialAccount__index 也是SpecialAccount。这样,s继承了SpecialAccount,后者继承了Account。当我们执行:

s:deposit(100.00)

Luas中找不到deposit域,他会到SpecialAccount中查找,在SpecialAccount中找不到,会到Account中查找。使得SpecialAccount特殊之处在于,它可以重定义从父类中继承来的方法:

function SpecialAccount:withdraw (v)

    if v - self.balance >= self:getLimit() then

       error"insufficient funds"

    end

    self.balance = self.balance - v

end

 

function SpecialAccount:getLimit ()

    return self.limit or 0

end

现在,当我们调用方法s:withdraw(200.00)Lua不会到Account中查找,因为它第一次救在SpecialAccount中发现了新的withdraw方法,由于s.limit等于1000.00(记住我们创建s的时候初始化了这个值)程序执行了取款操作,sbalance变成了负值。

Lua中面向对象有趣的一个方面是你不需要创建一个新类去指定一个新的行为。如果仅仅一个对象需要特殊的行为,你可以直接在对象中实现,例如,如果账号s表示一些特殊的客户:取款限制是他的存款的10%,你只需要修改这个单独的账号:

function s:getLimit ()

    return self.balance * 0.10

end

这样声明之后,调用s:withdraw(200.00)将运行SpecialAccountwithdraw方法,但是当方法调用self:getLimit时,最后的定义被触发。


相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛