Lua面向?qū)ο笾?lèi)和繼承
終于來(lái)了,在Lua中的面向?qū)ο缶幊?,相信目前學(xué)習(xí)Lua的大部分人都是為了開(kāi)發(fā)手機(jī)網(wǎng)游吧。
而且基本都是奔著腳本語(yǔ)言的熱更新特性去的,所以全腳本開(kāi)發(fā)變得十分流行。
對(duì)于普及不太廣的Lua(相對(duì)于C++、Java等主流語(yǔ)言),需要短時(shí)間上手開(kāi)發(fā)游戲,對(duì)新手而言不算簡(jiǎn)單。
所以大家才更習(xí)慣于繼續(xù)用面向?qū)ο笏枷肴フ垓vLua吧~
好了,不嘮叨了,我最不喜歡嘮叨了。(小若:是是是,你一點(diǎn)都不嘮叨,趕緊開(kāi)講?。?/p>
1.類(lèi)的對(duì)象
至于如何創(chuàng)建一個(gè)類(lèi),大家已經(jīng)很清楚了,就是一個(gè)table而已。
那么,要使用這個(gè)類(lèi)去創(chuàng)建多個(gè)對(duì)象,又如何實(shí)現(xiàn)呢?
使用元表和元方法即可。
如下代碼:
TSprite = {
x = 0,
y = 0,
}
function TSprite:setPosition(x, y)
self.x = x;
self.y = y;
end
function TSprite:new()
o = {}
setmetatable(o, {__index = self});
return o;
end
local who1 = TSprite:new();
local who2 = TSprite:new();
who1:setPosition(1, 2);
who2:setPosition(44, 6);
print("who1坐標(biāo)(" .. who1.x .. "," .. who1.y .. ")");
print("who2坐標(biāo)(" .. who2.x .. "," .. who2.y .. ")");
留意TSprite的new函數(shù),函數(shù)里創(chuàng)建了一個(gè)新的table,并且給新的table設(shè)置一個(gè)元表,這個(gè)元表的__index元方法就是TSprite本身,最后返回這個(gè)新的table。
于是,所有通過(guò)new生成的新table,都可以使用TSprite的函數(shù)和各個(gè)字段屬性(因?yàn)開(kāi)_index的值是TSprite)。
因此,我們利用new函數(shù)創(chuàng)建了who1和who2,并且調(diào)用它們的setPosition函數(shù),最后,who1和who2的x、y值都是不同的。
這就是類(lèi)的對(duì)象了。
2.類(lèi)對(duì)象的__index都是同一個(gè)TSprite,為什么x、y值可以不相同?
不知道大家有沒(méi)有這樣一個(gè)疑惑,那就是,為什么who1和who2的x、y是不一樣的,它們最終調(diào)用的不是setPosition函數(shù)么?調(diào)用self.x時(shí)最終不是調(diào)用了TSprite的x值么?
這里是會(huì)有點(diǎn)混亂,理一理就沒(méi)問(wèn)題了:
1). 當(dāng)who1里不存在setPosition時(shí),回去__index元方法里查找,于是,會(huì)找到TSprite的setPosition函數(shù)
2). 在setPosition函數(shù)里,使用了self.x = x,此時(shí)的self就是who1,who1中是不存在x字段的,所以,如果我們要打印self.x的值,則其實(shí)是打印了TSprite的x值
3). 但是,注意,但是來(lái)了。__index元方法是用于調(diào)用的,而不是用于賦值的,因此,self.x = x這句話,其實(shí)只是給who1這個(gè)table的x字段賦值了,who1本身不存在x字段,此時(shí)給它賦值了,于是who1存在了x字段,以后who1都不會(huì)再去TSprite里查找x字段了。
4). 因此,對(duì)who1和who2的x、y字段進(jìn)行賦值操作時(shí),是完全不會(huì)影響到TSprite的。
3.節(jié)省資源——使用TSprite作為元表
我們?cè)僮屑?xì)觀察一下new函數(shù),我們?cè)诮o新table設(shè)置元表的時(shí)候,是重新創(chuàng)建了一個(gè)元表的:setmetatable(o, {__index = self});
這么做的話,每次調(diào)用new函數(shù)創(chuàng)建一個(gè)新對(duì)象時(shí),都會(huì)產(chǎn)生一個(gè)新的元表,雖然這開(kāi)支似乎可以忽略,但,擁有強(qiáng)迫癥的你,一定很喜歡下面的代碼:
function TSprite:new()
o = {}
setmetatable(o, self);
self.__index = self;
return o;
end
在這段新的new函數(shù)里,使用self作為元表,然后又使用self作為_(kāi)_index的值。
這么一看,有點(diǎn)繞不過(guò)來(lái),我就喜歡大家繞不過(guò)來(lái),這樣我又可以嘮叨了:
1). 調(diào)用new函數(shù)時(shí),self其實(shí)就是TSprite本身,這里完全可以用TSprite代替,不過(guò),為了給以后做鋪墊,這里還是使用self吧。
2). self.__index = self,不要被這句代碼嚇到了,其實(shí)還是那么一回事,設(shè)置元表的__index元方法,這里就 相當(dāng)于TSprite.__index = TSprite。
3). TSprite自己作為_(kāi)_index的值沒(méi)問(wèn)題么?確實(shí)沒(méi)問(wèn)題,TSprite也是一個(gè)table,table可以作為元表,元表可以有__index元方法,這絲毫沒(méi)有英雄。
4). 于是,通過(guò)這個(gè)小技巧,我們就避免了每次調(diào)用new函數(shù)時(shí)都額外創(chuàng)建一個(gè)新的元表了。
4.富二代什么的我才不喜歡——繼承
我們總是笑話富二代,但誰(shuí)的內(nèi)心深處不希望自己是一個(gè)富二代呢~
像我這種立志靠自己成為富一代的人,可不多了~(小若:啊我呸~?。?br />
那么,在Lua里如何實(shí)現(xiàn)繼承呢?很簡(jiǎn)單,但是需要認(rèn)真思考,如下代碼:
TSprite = {
x = 0,
y = 0,
}
function TSprite:setPosition(x, y)
self.x = x;
self.y = y;
end
function TSprite:new()
o = {}
setmetatable(o, self);
self.__index = self;
return o;
end
local MoneySprite = TSprite:new();
function MoneySprite:setPosition(x, y)
print("呵呵,我是富二代,根本不需要改變。");
end
TSprite仍然沒(méi)變,但是,我們看看MoneySprite,按之前的理解,它是TSprite的一個(gè)對(duì)象。
只是,“對(duì)象”這稱(chēng)呼是我們自己定的,實(shí)際上它還是一個(gè)table而已。
此時(shí),我們修改了MoneySprite的setPosition函數(shù),于是,調(diào)用MoneySprite的setPosition函數(shù)時(shí),與TSprite無(wú)關(guān)了。
但,這不是重點(diǎn),重點(diǎn)是接下來(lái)的代碼:
local who = MoneySprite:new();
who:setPosition(44, 6);
print("who坐標(biāo)(" .. who.x .. "," .. who.y .. ")");
我們?cè)俅握{(diào)用MoneySprite的new函數(shù)創(chuàng)建了一個(gè)新對(duì)象。
這又是什么情況呢?關(guān)鍵是new函數(shù)里的代碼,此時(shí),new函數(shù)里的self是誰(shuí)?
new函數(shù)是由MoneySprite調(diào)用的,因此,self就是MoneySprite。
于是新對(duì)象的元表就是MoneySprite,元表的__index也是MoneySprite。
因此~!很神奇的,調(diào)用who的setPosition函數(shù)的時(shí)候,其實(shí)也是調(diào)用了MoneySprite的setPosition函數(shù)。
于是,who就是是MoneySprite的對(duì)象,而MoneySprite就是TSprite的子類(lèi)。
來(lái)看看輸出結(jié)果吧:
[LUA-print] 呵呵,我是富二代,根本不需要改變。
[LUA-print] who坐標(biāo)(0,0)
怎么樣?繼承的實(shí)現(xiàn)方法也很簡(jiǎn)單吧?
如果對(duì)元表、元方法、self比較生疏的話,可能一時(shí)間會(huì)理解不過(guò)來(lái),沒(méi)關(guān)系,多思考一會(huì),或者隔天再回頭思考,就會(huì)豁然開(kāi)朗了。
5.結(jié)束
不知不覺(jué)這個(gè)系列的文章已經(jīng)寫(xiě)了20篇了,真是太出乎我的意料了。
我竟然可以堅(jiān)持下來(lái),但寫(xiě)文章的效果確實(shí)很好,每晚的1個(gè)多小時(shí)付出也很值得。
起碼,我對(duì)Lua基礎(chǔ)的理解又更加鞏固了~
好吧,繼續(xù)堅(jiān)持…(小若:所以說(shuō)啊~!為什么每次都要用省略號(hào),用感嘆號(hào)不是更能表達(dá)你的決心嗎…)
- Lua中的string庫(kù)(字符串函數(shù)庫(kù))總結(jié)
- Lua中的函數(shù)(function)、可變參數(shù)、局部函數(shù)、尾遞歸優(yōu)化等實(shí)例講解
- Lua中的一些常用函數(shù)庫(kù)實(shí)例講解
- Lua中的模塊與module函數(shù)詳解
- Lua中的函數(shù)知識(shí)總結(jié)
- Lua字符串庫(kù)中的幾個(gè)重點(diǎn)函數(shù)介紹
- Lua的table庫(kù)函數(shù)insert、remove、concat、sort詳細(xì)介紹
- Lua中的常用函數(shù)庫(kù)匯總
- Lua中的面向?qū)ο缶幊淘斀?/a>
- Lua面向?qū)ο笾嘀乩^承、私密性詳解
- Lua面向?qū)ο缶幊虒W(xué)習(xí)筆記
- Lua中函數(shù)與面向?qū)ο缶幊痰幕A(chǔ)知識(shí)整理
相關(guān)文章
Lua教程(一):簡(jiǎn)介、優(yōu)勢(shì)和應(yīng)用場(chǎng)景介紹
這篇文章主要介紹了Lua教程(一):簡(jiǎn)介、優(yōu)勢(shì)和應(yīng)用場(chǎng)景介紹,本文是Lua教程系列文章的第一篇,需要的朋友可以參考下2015-04-04Nginx+lua 實(shí)現(xiàn)調(diào)用.so文件
本文給大家分享的是Nginx結(jié)合lua 實(shí)現(xiàn)調(diào)用.so動(dòng)態(tài)鏈接庫(kù)文件的方法和示例,有需要的小伙伴可以參考下2017-05-05如何使用Vim搭建Lua開(kāi)發(fā)環(huán)境詳解
這篇文章主要給大家介紹了關(guān)于如何使用Vim搭建Lua開(kāi)發(fā)環(huán)境的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02Lua 數(shù)學(xué)庫(kù)的所有函數(shù)功能作用一覽
這篇文章主要介紹了Lua 數(shù)學(xué)庫(kù)的所有函數(shù)功能作用一覽,本文羅列了lua數(shù)學(xué)庫(kù)的所有函數(shù),并對(duì)每個(gè)函數(shù)的功能作用做了簡(jiǎn)短描述,需要的朋友可以參考下2015-06-06Lua中計(jì)算、執(zhí)行字符串中Lua代碼的方法
這篇文章主要介紹了Lua中計(jì)算、執(zhí)行字符串中Lua代碼的方法,類(lèi)似JavaScript中eval函數(shù)的功能,在Lua中也可以實(shí)現(xiàn),需要的朋友可以參考下2015-05-05vs2012 error c4996: This function or variable may be unsafe
這篇文章主要介紹了vs2012 error c4996: This function or variable may be unsafe,需要的朋友可以參考下2015-04-04