Chapter 16_3 多重继承

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

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

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

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

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

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

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

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

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

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

创建新类的代码:

--在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
    end
end

function 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 》

posted @ 2016-09-18 18:55  daiker  阅读(208)  评论(0编辑  收藏  举报