基于Lua实现类的继承

基于metatable可以实现OOP中继承相关的内容,如下代码所示。

--[[

Create a class "Animal" with properties:height,weight,name,sound
and methods: new,getInfo,saySomething

]]

-- Define the defaults for our table
Animal = { height = 0, weight = 0, name = "No Name", sound = "No Sound" }

-- Constructor
function Animal:new(height, weight, name, sound)
    -- Create a new instance table
    local instance = {}
    -- Set Animal as the metatable for the new instance
    setmetatable(instance, { __index = Animal })
    -- Assign instance variables
    instance.height = height
    instance.weight = weight
    instance.name = name
    instance.sound = sound
    -- Return the new instance
    return instance
end

-- Some method
function Animal:getInfo()
    local animalStr = string.format("%s weighs %.1f kg, is %.1fm in tall", self.name, self.weight, self.height)
    return animalStr
end

function Animal:saySomething()
    print(self.sound)
end

-- Create an Animal
local flop = Animal:new(1, 10.5, "Flop", "Auau")
print(flop.name)      -- same as flop["name"]
print(flop:getInfo()) -- same as flop.getInfo(flop)
print(flop:saySomething())

-- Other way to say the samething
print(flop["name"])
print(flop.getInfo(flop))

-- Type of our object
print(type(flop))

-- 参考Lua官方给的代码
http://lua-users.org/wiki/ClassesAndMethodsExample

学习如何基于Lua脚本实现继承和面向对象的机制。

下面是测试代码。

-- object test.lua
require("INC_Class")

--===========================

local cAnimal = SETclass("Animal")


function cAnimal.methods:init(action, cutename)
	self.superaction = action
	self.supercutename = cutename
end

--==========================

local cTiger = SETclass("Tiger", cAnimal)

function cTiger.methods:init(cutename)
	self:init_super("HUNT (Tiger)", "Zoo Animal (Tiger)")
	self.action = "ROAR FOR ME!!"
	self.cutename = cutename
end

--==========================

Tiger1 = cAnimal:new("HUNT", "Zoo Animal")
Tiger2 = cTiger:new("Mr Grumpy")
Tiger3 = cTiger:new("Mr Hungry")

print("CLASSNAME FOR TIGER1 = ", Tiger1:classname())
print("CLASSNAME FOR TIGER2 = ", Tiger2:classname())
print("CLASSNAME FOR TIGER3 = ", Tiger3:classname())
print("===============")
print("SUPER ACTION", Tiger1.superaction)
print("SUPER CUTENAME", Tiger1.supercutename)
print("ACTION        ", Tiger1.action)
print("CUTENAME", Tiger1.cutename)
print("===============")
print("SUPER ACTION", Tiger2.superaction)
print("SUPER CUTENAME", Tiger2.supercutename)
print("ACTION        ", Tiger2.action)
print("CUTENAME", Tiger2.cutename)
print("===============")
print("SUPER ACTION", Tiger3.superaction)
print("SUPER CUTENAME", Tiger3.supercutename)
print("ACTION        ", Tiger3.action)
print("CUTENAME", Tiger3.cutename)

下面是INC_Class.lua文件,代码中的arg变量是需要手动定义的!

-- INC_Class.lua
-----------------------------------------------------
---- SETCLASS CLONES THE BASIC OBJECT CLASS TO CREATE NEW CLASSES
-----------------------------------------------------
-- Supports INHERITANCE
--
-- Sam Lie, 17 May 2004
-- Modified Code from Christian Lindig - lindig (at) cs.uni-sb.de
---------------------------------------------------------------

-- EVERYTHING INHERITS FROM THIS BASIC OBJECT CLASS
BaseObject = {
    super   = nil,
    name    = "Object",
    new     =
        function(class)
            local obj  = { class = class }
            local meta = {
                __index = function(self, key) return class.methods[key] end
            }
            setmetatable(obj, meta)
            return obj
        end,
    methods = { classname = function(self) return (self.class.name) end },
    data    = {}
}

function SETclass(name, super)
    if (super == nil) then
        super = BaseObject
    end

    local class = {
        super   = super,
        name    = name,
        new     =
            function(self, ...)
                local arg = { ... }

                local obj = super.new(self, "___CREATE_ONLY___");
                -- check if calling function init
                -- pass arguments into init function
                if (super.methods.init) then
                    obj.init_super = super.methods.init
                end

                if (self.methods.init) then
                    if (tostring(arg[1]) ~= "___CREATE_ONLY___") then
                        obj.init = self.methods.init
                        if obj.init then
                            obj:init(table.unpack(arg))
                        end
                    end
                end

                return obj
            end,
        methods = {}
    }

    -- if class slot unavailable, check super class
    -- if applied to argument, pass it to the class method new
    setmetatable(class, {
        __index = function(self, key) return self.super[key] end,
        __call  = function(self, ...) return self.new(self, table.unpack(arg)) end
    })

    -- if instance method unavailable, check method slot in super class
    setmetatable(class.methods, {
        __index = function(self, key) return class.super.methods[key] end
    })
    return class
end
posted @ 2024-05-04 21:12  ckxkexing  阅读(14)  评论(0编辑  收藏  举报