2011-08-03 110 views
2

我在Lua有兩個類。一個繼承另一個。Lua類繼承問題

test1 = {test1Data = 123, id= {0,3}} 
function test1:hello() 
    print 'HELLO!' 
end 
function test1:new (inp) 
    inp = inp or {} 
    setmetatable(inp, self) 
    self.__index = self 
    return inp 
end 
test2 = {} 
function test2:bye() 
    print ('BYE!', self.id) 
end 
function test2:new_inst_test (baseClass, inp) 
    inp = inp or {} 
    setmetatable(inp, self) 
    self.__index = self 
    if baseClass then 
     setmetatable(inp, { __index = baseClass }) 
    end 
    return inp 
end 

a = test1:new({passData='abc1'}) 
b = test1:new({passData='ghyrty'}) 

c = test2:new_inst_test(a,{temp = '123343321135'}) 
d = test2:new_inst_test(b, {temp = '1'}) 



print (c.temp, c.test1Data, c.passData) 
print (d.temp, d.test1Data, d.passData) 
c:bye() 
c:hello() 

我想test2不只是繼承test1,而是保存自己的方法('bye')。 這可能嗎? 謝謝!

+0

[Lua繼承問題]可能的重複(http://stackoverflow.com/questions/6917516/lua-inheritance-question) – Roddy

回答

7

你應該在class metatable上設置一個帶有__index = baseclass的metatable我認爲。但是這會改變test2類中所有對象的metatable。這樣做,您將使用類本身的方法,並且只在方法不存在於當前類中時才使用來自父類的方法,或者它是可交換的。

所以應該像

if baseClass then 
    setmetatable(self, { __index = baseClass }) 
end 

在另一方面,它是一種奇怪的,你只能做一個新的實例時,而不是創建新類時指定它指定基類。 所以我會重新考慮如何在類之間繼承,而不是在實例和類之間繼承。

作爲一個小魔法爲主題的例子:

--oop.lua Example of OOP and inheritance in Lua 
Person={ 
    age=0, 
    className='Person' 
} 
-- needed if needed add comparisons, operations, ... 
mtPerson={} 
mtPerson.__index={ 
    getClassName=function(self) 
     return self.className 
    end, 
    new=function(self,t)  
     return setmetatable(t or {},{__index=self}) 
    end, 
    inherit=function (self,t,methods) 
     -- This is the heart of the inheritance: It says: 
     -- Look it up in the methods table, and if it's not there, look it up in the parrent class (her called self) 
     -- You pass this function the parent class (with :), a table of attributes and a table of methods. 
     local mtnew={__index=setmetatable(methods,{__index=self})} 
     return setmetatable(t or {},mtnew) 
    end, 
    introduce=function(self) 
     print(("Hi! I'm %s, I'm a %s and I'm %d years old"):format(self.instanceName,self.className,self.age)) 
    end 
    } 

setmetatable(Person,mtPerson) 

-- Wizard inherits from the class Person, and adds some default values and methods 
Wizard=Person:inherit({ 
    className="Wizard", 
    knownSpells={}, 
    }, 
    { 
    listSpells=function(self) 
     print("known spells:",self) 
     if #self.knownSpells==0 then 
      print'none' 
     else 
      for k,v in ipairs(self.knownSpells) do 
       print(k,v) 
      end 
     end 
    end 
    } 
) 

i1=Person:new{ 
    inventory={'wallet'}, 
    instanceName="John", 
} 

i2=Wizard:new{ -- inherited method "new" 
    inventory={'wallet','wand','cloak of invisibility'}, 
    instanceName="Harry", 
    age=20, 
    knownSpells={'Avada kavedra', 'Sesame open'} 
} 

i1:introduce() -- inherited method "introduce" notice that qge is the default value of 0 
i2:introduce() -- 

i2:listSpells() -- method only in class 2 
i1.age=26 
i1:introduce() -- changed age of instance 
print(Person.age) -- didn't change class defaults 
print(Wizard.age) 
i1:listSpells() -- Error. 

在寫這個,我來到壽的結論是OOP在Lua是在同一時間很簡單,也很複雜。在編寫代碼之前,你只需要真正地思考問題,然後再堅持這個計劃。因此,我在這裏選擇將屬性放在類和實例表本身中,並將所有方法放在它們各自的元表中。我這樣做是因爲現在很容易遍歷所有屬性,而不會遇到方法,但任何可行的選擇都是有效的。你只需要選擇一個。

+0

我知道,它可能看起來很奇怪。我只想創建類的可能性,這將是2類(它將具有所有的方法和變量)的'總和' – cyhiso

+0

如果你像我說的那樣實現它,它會。方法和變量的優先級將如下所示:首先是實例的變量和方法,然後是實例所屬類中的變量,然後是實例的類繼承的類中的變量和方法。您應該做的唯一事情是在創建類時指定繼承,而不是在創建實例時指定繼承。這是因爲每次指定不同的基類時,它將改變整個類,而不僅僅是您創建的實例。 – jpjacobs

+0

,你能寫一個小例子嗎?)我會非常感激。導致我相當新的Lua和我完全卡在這個繼承... – cyhiso