2010-11-11 73 views
6

元方法我非常喜歡怎樣的面向對象編程中的「編程LUA」 16.1,16.2描述:繼承了在Lua

http://www.lua.org/pil/16.1.html

http://www.lua.org/pil/16.2.html

,並希望採用這種做法。但我想進一步採取一些事情:我想有一個名爲「類」的基類「class」,它應該是所有子類的基礎,因爲我想在那裏實現一些輔助方法(如「instanceof」等。),但實質上在書中描述應該是:

我的問題
function class:new(o) 
    o = o or {} 
    setmetatable(o, self) 
    self.__index = self 
    return o 
end 

現在:

我想有一類「數字」,從「類」繼承:

number = class:new() 

我想爲操作符重載(__add,__sub等)定義metamethods in這個類,所以像這樣:

n1 = number:new() 
n2 = number:new() 

print(n1 + n2) 

工程。這不是一個真正的問題。但現在我想有一個從「數字」繼承的第三類「金錢」:

money = number:new{value=10,currency='EUR'} 

我在這裏介紹了一些新的屬性。

現在我的問題是,我沒有得到的東西工作,「錢」繼承「類」和「數字」所有方法,包括所有metamethods中定義的「數量」。

我已經嘗試了幾件事情,像覆蓋「新」或修改metatables,但我無法讓事情工作,沒有丟失「錢」中的「類」的方法或失去「數字」在「錢」

我知道,那裏有很多的類實現,但我真的想堅持lua本身的最小途徑。

任何幫助將非常感謝!

非常感謝!

回答

3

我認爲你遇到的問題是由於運營商metamethods使用類似於rawget(getmetatable(obj) or {}, "__add")類似的東西。因此,操作員不會與其他功能一起繼承。

我已經取得了一些成功具有new功能複製經營者是這樣的:

function class:new(o) 
    o = o or {} 
    setmetatable(o, self) 
    self.__index = self 
    local m=getmetatable(self) 
    if m then 
     for k,v in pairs(m) do 
      if not rawget(self,k) and k:match("^__") then 
       self[k] = m[k] 
      end 
     end 
    end 
    return o 
end 
+0

謝謝,它的工作原理! – aurora 2010-11-19 15:40:59

+0

好的解決方案。爲了避免在所有基類中重複這一點,我爲它們創建了一個頂級的'Class'。做這項工作的訣竅是向它們的構造函數中添加'o = Class.new(self)',以防覆蓋構造函數。 – Ludwik 2016-03-26 08:57:15

0

我沒有類似的東西,有一個類似的問題。這裏是我的基礎類定義:

RootObjectType = {} 
RootObjectType.__index = RootObjectType 
function RootObjectType.new(o) 
     o = o or {} 
     setmetatable(o, RootObjectType) 
     o.myOid = RootObjectType.next_oid() 
     return o 
end 

function RootObjectType.newSubclass() 
     local o = {} 
     o.__index = o 
     setmetatable(o, RootObjectType) 
     RootObjectType.copyDownMetaMethods(o, RootObjectType) 
     o.baseClass = RootObjectType 
     return o 
end 

function RootObjectType.copyDownMetaMethods(destination, source) -- this is the code you want 
     destination.__lt = source.__lt 
     destination.__le = source.__le 
     destination.__eq = source.__eq 
     destination.__tostring = source.__tostring 
end 

RootObjectType.myNextOid = 0 
function RootObjectType.next_oid() 
     local id = RootObjectType.myNextOid 
     RootObjectType.myNextOid = RootObjectType.myNextOid + 1 
     return id 
end 

function RootObjectType:instanceOf(parentObjectType) 
     if parentObjectType == nil then return nil end 
     local obj = self 
     --while true do 
     do 
       local mt = getmetatable(obj) 
       if mt == parentObjectType then 
         return self 
       elseif mt == nil then 
         return nil 
       elseif mt == obj then 
         return nil 
       else 
         obj = mt 
       end 
     end 
     return nil 
end 


function RootObjectType:__lt(rhs) 
     return self.myOid < rhs.myOid 
end 

function RootObjectType:__eq(rhs) 
     return self.myOid == rhs.myOid 
end 

function RootObjectType:__le(rhs) 
     return self.myOid <= rhs.myOid 
end 

function RootObjectType.assertIdentity(obj, base_type) 
     if obj == nil or obj.instanceOf == nil or not obj:instanceOf(base_type) then 
       error("Identity of object was not valid") 
     end 
     return obj 
end 

function set_iterator(set) 
     local it, state, start = pairs(set) 
     return function(...) 
       local v = it(...) 
       return v 
     end, state, start 
end 
+0

非常感謝! – aurora 2010-11-19 15:39:59

2

這個問題已經回答了,但讓我介紹我對於這個問題,我發展我的OOP的lib,middleclass當打前一段時間的解決方案。

在我的情況下,我開始做所有的「有用的」元方法的名稱列表:

local _metamethods = { -- all metamethods except __index 
    '__add', '__call', '__concat', '__div', '__le', '__lt', '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm' 
} 

我使用該列表的方法添加到創建的每個類。所以,實際上,我對所有的元方法「默認實現」:

-- creates a subclass 
function Object.subclass(theClass, name) 
    ... 

    local dict = theSubClass.__classDict -- classDict contains all the [meta]methods of the 
    local superDict = theSuperClass.__classDict -- same for the superclass 
    ... 

    for _,mmName in ipairs(_metamethods) do -- Creates the initial metamethods 
    dict[mmName]= function(...) -- by default, they just 'look up' for an implememtation 
     local method = superDict[mmName] -- and if none found, they throw an error 
     assert(type(method)=='function', tostring(theSubClass) .. " doesn't implement metamethod '" .. mmName .. "'") 
     return method(...) 
    end 
    end 

的訣竅是默認的實現「呼叫」父類的實現;如果不存在,則會引發錯誤。用這種方式實現的元方法只比常規方法稍慢(2個額外的方法調用),而且使用的內存量非常小(每個類有12個額外的函數)。

PS:我沒有包含__len metamethod,因爲Lua 5.1並不尊重它。

PS2:我沒有包含__index__newindex,因爲我必須在內部爲我的類使用它們。

+0

感謝分享...我會仔細看看你的方法。 – aurora 2011-03-25 20:40:59