Проблема наследования классов Lua - PullRequest
2 голосов
/ 03 августа 2011

У меня есть два класса в 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, но и сохранял собственные методы ('пока').Является ли это возможным?Спасибо!

1 Ответ

7 голосов
/ 03 августа 2011

Вы должны установить метатабельный с __index = baseclass для класса метатабельного, я думаю.Но это изменит метатабель для всех объектов в классе test2.Делая это таким образом, вы будете использовать методы из самого класса и использовать методы из родительского класса только в том случае, если метод не существует в текущем классе или его можно метатизировать.

Так что это должно быть похоже на

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.

При написании этого я пришел к выводу, что ООПв Lua это в то же время очень просто и очень сложно.Вы просто должны действительно продумать вещи до написания кода и придерживаться плана позже.Таким образом, здесь я решил поместить атрибуты в сами таблицы классов и экземпляров и поместить все методы в соответствующие им метатаблицы.Я сделал это, потому что теперь легко перебирать все атрибуты, не встречая методов, но любой выбор, который работает, действителен.Вам просто нужно выбрать один.

...