首先咱們去了解一下類,一個類就是一個建立對象的模具,實際上,lua中不存在類這個概念,咱們都是去模擬類。在lua中,要表示一個類,只需建立一個專用做其它對象的原型。咱們在lua的面相對象,就是使用table,元表以及元方法,咱們如今看一下具體事怎麼作的:
編程
咱們如今有兩個對象a和b,如今想b做爲a的原型,只需編寫下面代碼便可:函數
setmetatable(a,{__index = b})
咱們前面有講過__index,編寫完這段代碼以後,當lua執行了a沒有的操做的時候,就會去b中查詢。實際上咱們也能夠稱b事對象a的類;咱們要建立一個對象,必需要有一個原型,這就是「類」。以下:lua
local man = {num = 0}
如今咱們有原型類,接着咱們使用這個原型建立一個「實例」,首先咱們先編寫man的new函數:spa
function man:new(o) o = o or {} --若是o爲nil,則將o複製爲{} setmetatable(o,self) self.__index = self return o end function man:sayhi() self.num = self.num + 1 print("已經打招呼的人" .. self.num) end
當咱們調用man的new函數的時候,self就至關於man。接着咱們來使用man的new函數來建立一個實例:code
local tom = man:new() tom:sayhi() tom:sayhi()
輸出:對象
已經打招呼的人1 已經打招呼的人2
咱們來看一下上面的代碼如何工做的,首先使用man的new函數去建立一個新的實例對象,並將man做爲新的實例對象tom的元表。當咱們調用tom:sayhi()時,lua就會去查找tom是否有sayhi這個字段,沒有的話就去搜索它的元表,調用的結果其實是:
繼承
getmetatable(tom).__index(sayhi(tom))
而tom的元表是man,man的__index也是man,上面的寫法實際上也是:get
man.sayhi(tom)
實際上,咱們上面也是涉及到了繼承的(sayhi函數)。接着咱們來探討一下lua的多繼承:
原型
咱們能夠能夠設置子類的metatable爲父類,並將父類的__index設置爲其自己來實現單繼承。而多繼承也是同樣的道理,不一樣的是單繼承中若是子類沒有對應的字段,則只需在一個父類中尋找這個不存在的字段,而多繼承則是須要在多個父類中尋找。io
因爲多繼承須要在多個父類中尋找,因此咱們不能像單繼承那樣,直接指向__index爲某個父類,而是應該指定__index爲一個函數,在這個函數中指定搜索不存在的字段的規則。這樣即可以實現多繼承。咱們看一下下面的例子:
-- 在多個父類中查找字段k local function search(k, pParentList) for i = 1, #pParentList do local v = pParentList[i][k] 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, self) -- self.__index = self 這裏不用設置了,在上面已經設置了c.__index = c return o end -- 返回新的類(原型) return c end -- 一個簡單的類CA local CA = {} function CA:new(o) o = o or {} setmetatable(o, {__index = self}) self.__index = self return o end function CA:setName(strName) self.name = strName end -- 一個簡單的類CB local CB = {} function CB:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end function CB:getName() return self.name end -- 建立一個c類,它的父類是CA和CB local c = createClass(CA, CB) -- 使用c類建立一個實例對象 local objectC = c:new{name = "Jelly"} -- 設置objectC對象一個新的名字 objectC:setName("JellyThink") local newName = objectC:getName() print(newName)
注:
使用createClass建立了一個類(原型),將CA和CB設置爲這個類(原型)的父類(原型);在建立的這個類(原型)中,設置了該類的__index爲一個search函數,在這個search函數中尋找在建立的類中沒有的字段;
建立的新類中,有一個構造函數new;這個new和以前的單繼承中的new區別不大,很好理解;
調用new構造函數,建立一個實例對象,該實例對象有一個name字段;
調用object:setName(「JellyThink」)語句,設置一個新的名字;可是在objectC中沒有這個字段,怎麼辦?好了,去父類找,先去CA找,一會兒就找到了,而後就調用了這個setName,setName中的self指向的是objectC;設置之後,就至關於修改了objectC字段的name值;
調用objectC:getName(),objectC仍是沒有這個字段。找吧,CA也沒有,那就接着找,在CB中找到了,就調用getName,在getName中的self指向的是objectC。因此,在objectC:getName中返回了objectC中name的值,就是「JellyThink」。
其實lua的類就是建立一個table,而後爲table綁定幾個方法,綁定幾個對象。而後在經過元表與元方法的一些操做從而完成lua的面相對象編程。