首页 > 代码库 > Chapter 16_3 多重继承

Chapter 16_3 多重继承

  在Lua中进行面向对象编程时有几种方法,上一小结介绍了一种使用__index元方法的做法。

下面要介绍另一种方法,可以在Lua中实现多继承.

  关键一点,在于用函数作为__index元字段

  多重继承意味着一个类可以有多个基类。因此无法使用一个类中的方法来创建子类,而是需要定义一个特殊的函数来创建

它的参数表示新类的所有基类。创建时它会设置元表中的__index元方法。而多重继承正是在这个__index元方法中完成的。

类和基类之间的关系不同于类和实例之间的关系。尤其是一个类不能同时作为其实例和子类的元表。

在下面的createClass例子中,将类作为其实例的元表,并创建了另一个table作为类的元表。

用之前的Account和新的一个类Named去实现createClass。

新的Named有两个方法,setname和getname

Named = {}function Named:getname()    return self.nameendfunction Named:setname(n)    self.name = nend

创建新类的代码:

--在table plist中查找"k"local function search(k , plist)    for i = 1, #plist do        local v = plist[i][k]    --尝试第i个基类        if v then return v end    endendfunction createClass(...)    local c = {}    --新类    local parents = {...}    --类在其父类列表中的搜索方法    setmetatable(c ,{__index = function( t , k )                            return search( k , parents)                        end                    })    --将‘c‘作为其实例的元表    c.__index = c    --为这个新类定义一个新的构造函数    function c:new(o)        o = o or {}        setmetatable(o,c)        return o        end    return c    --返回新类end

假设要创建一个新类NameAccount,同时从Account和Named派生,那么只需要调用createClass:

NamedAccount = createClass(Account,Named)

如果要创建并使用实例:

account = NamedAccount:new{name  = "Paul"}    --创建实例print(account:getname())    --> Paul    --使用实例

首先Lua在account中找不到“getname”。就查找account中的元表__index字段。该字段为NamedAccount。它也没有“getname”。

所以Lua就找NamedAccount的__index,结果是一个函数。该函数先在Account中查找,再在Named中查找(找到就结束了)。

由于这项搜索具有复杂性,所以多重继承性能不如单一继承。

一个改进方法是将继承的方法复制到子类中:

setmetatable(c , {__index = function (t, k )        local v = search ( k , parents )        t[k] = v    --保存下来,以备下次访问        return v    end})

一个缺点:当系统运行后就较难修改方法的定义,因为这些改变不会沿着继承向下传播。

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》

Chapter 16_3 多重继承