继承教程

lua-users home
wiki

本教程演示了在 Lua 中实现面向对象继承的技术。在继续之前,建议您熟悉 面向对象教程元方法教程

简单类

以下示例实现了一个没有继承的类

SimpleClass = {}
SimpleClass_mt = { __index = SimpleClass }

-- This function creates a new instance of SimpleClass
--
function SimpleClass:create()
    local new_inst = {}    -- the new instance
    setmetatable( new_inst, SimpleClass_mt ) -- all instances share the same metatable
    return new_inst
end

-- Here are some functions (methods) for SimpleClass:

function SimpleClass:className()
    print( "SimpleClass" )
end

function SimpleClass:doSomething()
    print( "Doing something" )
end

在上面的示例中,SimpleClass 代表一个表,它保存了我们类中的所有方法,就像一个类声明。SimpleClass_mt 是我们将附加到每个创建的类实例的元表。函数 SimpleClass:create() 创建我们类 SimpleClass 的一个实例。创建类实例涉及创建一个空表,然后将我们的 SimpleClass 元方法附加到它。附加元方法的结果是,新实例会查看我们附加的元表以获取其自定义行为。

对实例进行方法调用将触发实例上的“索引”事件,导致在实例元表的“__index”成员上进行查找。__index 成员只是一个对 SimpleClass 的引用。因此,对实例进行方法调用将导致在 SimpleClass 表中进行查找。

以下是一个示例

> simple = SimpleClass:create()
> 
> simple:className()
SimpleClass
> 
> simple:doSomething()
Doing something

实现继承

现在我们想要创建一个新的类 SubClass,它继承并可选地覆盖来自 SimpleClass 的函数。

-- Create a new class that inherits from a base class
--
function inheritsFrom( baseClass )

    -- The following lines are equivalent to the SimpleClass example:

    -- Create the table and metatable representing the class.
    local new_class = {}
    local class_mt = { __index = new_class }

    -- Note that this function uses class_mt as an upvalue, so every instance
    -- of the class will share the same metatable.
    --
    function new_class:create()
        local newinst = {}
        setmetatable( newinst, class_mt )
        return newinst
    end

    -- The following is the key to implementing inheritance:

    -- The __index member of the new class's metatable references the
    -- base class.  This implies that all methods of the base class will
    -- be exposed to the sub-class, and that the sub-class can override
    -- any of these methods.
    --
    if baseClass then
        setmetatable( new_class, { __index = baseClass } )
    end

    return new_class
end

函数 inheritsFrom(baseClass) 接受一个参数,即我们要继承的类声明。该函数返回一个类声明,我们可以对其进行定制。new_class 是要返回的新类声明。嵌套函数 new_class:create() 是返回的类声明的一部分,它将创建我们正在创建的子类的新的实例。此函数创建一个 newinst 表,该表使用我们的新类表来保存其方法。新的类表反过来会在找不到我们需要的某个方法时在 baseClass 中查找,因此我们继承了它的方法。

继承示例

基于 SimpleClass,我们现在创建一个名为 SubClass 的类,它继承自 SimpleClass 并覆盖 className()

> -- Create a new class that inherits from SimpleClass
> SubClass = inheritsFrom( SimpleClass )
>
> -- override className() function
> function SubClass:className() print( "SubClass" ) end
>
> -- Create an instance of SimpleClass
> simple = SimpleClass:create()
> 
> simple:className()
SimpleClass



> 
> simple:doSomething()
Doing something
> 
> -- Create an instance of SubClass
> sub = SubClass:create()
> 
> sub:className()  -- Call overridden method
SubClass
> 
> sub:doSomething()  -- Call base class method
Doing something
> 

OO 属性

我们现在可以扩展我们的继承结构并添加其他语言中常见的特性,例如访问类的超类和提供类型 ID 功能的 isa() 方法

-- A new inheritsFrom() function
--
function inheritsFrom( baseClass )

    local new_class = {}
    local class_mt = { __index = new_class }

    function new_class:create()
        local newinst = {}
        setmetatable( newinst, class_mt )
        return newinst
    end

    if nil ~= baseClass then
        setmetatable( new_class, { __index = baseClass } )
    end

    -- Implementation of additional OO properties starts here --

    -- Return the class object of the instance
    function new_class:class()
        return new_class
    end

    -- Return the super class object of the instance
    function new_class:superClass()
        return baseClass
    end

    -- Return true if the caller is an instance of theClass
    function new_class:isa( theClass )
        local b_isa = false

        local cur_class = new_class

        while ( nil ~= cur_class ) and ( false == b_isa ) do
            if cur_class == theClass then
                b_isa = true
            else
                cur_class = cur_class:superClass()
            end
        end

        return b_isa
    end

    return new_class
end

以及一个使用示例

> SimpleClass = inheritsFrom( nil )  -- pass nil because SimpleClass has no super class
> 
> SubClass = inheritsFrom( SimpleClass )
> 
> FinalClass = inheritsFrom( SubClass )
> 
> sub = SubClass:create()
> fc = FinalClass:create()
> 
> print( fc:isa( SubClass ) )
true
> print( fc:isa( FinalClass ) )
true
> print( sub:isa( SubClass ) )
true
> print( sub:isa( FinalClass ) )
false

替代方法:基于原型

基于原型的编程是一种面向对象的编程风格,其中没有类,行为重用(在基于类的语言中称为继承)是通过克隆用作原型的现有对象来执行的。这种模型也可以称为无类、面向原型或基于实例的编程。

[维基百科关于基于原型的编程的条目]

大部分代码与上面基本相同,但简化为仅包含使“基于原型的编程”起作用所需的必要内容。更准确地说,它允许使用克隆和原型委托进行原型编程。对未在对象中设置的属性的访问被委托给它的原型。此代码使用table表作为最基本的原型,object作为table的特殊化。函数object.isa对于原型范式来说并不是严格必需的,但更方便。

函数clone(base_object[, clone_object]) -> table

参数

返回值

如果new_object不是table类型,则如果它不是nil,则返回new_object,在这种情况下返回base_objectnew_object的元表设置为自身,并且它的__index现在指向它的原型base_objectclone也可以作为object.clone使用。

它还可能存在将布尔值作为任一参数传递的问题,因为,嗯……作为读者的练习!? ;-)

函数isa( clone_object, base_object) -> bool

参数

返回值

如果两个参数都不是tableisa将回退到返回类型的比较。它也可以作为object.isa使用。

此函数在深层原型层次结构中将获得糟糕的性能。

代码

function clone( base_object, clone_object )
  if type( base_object ) ~= "table" then
    return clone_object or base_object 
  end
  clone_object = clone_object or {}
  clone_object.__index = base_object
  return setmetatable(clone_object, clone_object)
end

function isa( clone_object, base_object )
  local clone_object_type = type(clone_object)
  local base_object_type = type(base_object)
  if clone_object_type ~= "table" and base_object_type ~= table then
    return clone_object_type == base_object_type
  end
  local index = clone_object.__index
  local _isa = index == base_object
  while not _isa and index ~= nil do
    index = index.__index
    _isa = index == base_object
  end
  return _isa
end

object = clone( table, { clone = clone, isa = isa } )

示例

-- testing "isa"
foo = object:clone()
bar = object:clone()
baz = foo:clone()

print( foo:isa(object) )
print( bar:isa(foo) )
print( baz:isa(foo) )

--[[ output:
true
false
true
]]

--testing prototype delegation

foo = object:clone()
bar = foo:clone()

function foo:speak()
  print(self.thoughts or "foo has no thoughts")
end

bar:speak()

--[[ output:
foo has no thoughts
]]

bar.thoughts = "I may be a clone, but I'm an individual!"
bar:speak()

--[[ output:
I may be a clone, but I'm an individual!
]]


贡献者:KevinBaca

另请参阅


最近更改 · 偏好设置
编辑 · 历史
最后编辑于 2011 年 11 月 18 日下午 12:09 GMT (差异)