Lua实现继承
我们知道在
Lua脚本语言中是没有对象这个概念的。但是Lua为我们提供了一堆的元方法,可以实现类的继承
需求背景
- 实现类似
c++中的类 - 实现类对类的继承
- 实现类的多继承
什么是继承
继承是面向对象最显著的一个特性,继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
实现类似C++中的类
-
我们先不考虑继承的问题,首先来实现一个类的定义。
-
实现
local class = function (className) if type(className) ~= "string" then error("class name must string type") end local cls = {__className = className} cls.ctor = function ( ... ) -- default constructor end cls.new = function ( ... ) local instance = {} setmetatable(instance, {__index = cls}) instance.__class = cls instance.ctor(...) return instance end cls.create = function ( ... ) return cls.new(...) end return cls end -
测试
local ClassA = class("classA") function ClassA:ctor( ... ) print("ClassA:ctor params is ", ...) self.name = ... end function ClassA:sayHello() print(string.format("my name is %s", self.name)) end local classA_1 = ClassA:create("ClassA_1") classA_1:sayHello() print("=============================") local classA_2 = ClassA:create("ClassA_2") classA_2:sayHello() print("=============================") classA_1.name = "XXX" classA_1:sayHello() classA_2:sayHello() -
测试结果
ClassA:ctor params is ClassA_1 my name is ClassA_1 ============================= ClassA:ctor params is ClassA_2 my name is ClassA_2 ============================= my name is XXX my name is ClassA_2 [Finished in 0.0s]
-
-
错误演示
-
可能会有同学好奇,在测试代码中为什有如下代码
classA_1.name = "XXX" classA_1:sayHello() classA_2:sayHello()
这里是为了检测是否做到了由一个类,创建出来的两个对象是否做到了数据的隔离
-
将
class函数中的new函数做出如下修改,就会发现对象与对象之间数据混乱cls.new = function ( ... ) cls.ctor(...) return cls end -
使用上面测试代码测试结果为
ClassA:ctor params is ClassA_1 my name is ClassA_1 ============================= ClassA:ctor params is ClassA_2 my name is ClassA_2 ============================= my name is XXX my name is XXX [Finished in 0.0s]
注意:一定要做好数据隔离,不然创建出来的对象数据就会混乱。这里只为类创建添加了构造函数,没有添加析构函数,可以仿造上面添加一个
dtor析构函数 -
实现类对类的继承
在上面的取得的小成果上,继续扩展和完成
class函数,从而实现类对类的继承。其实在我们只需要借鉴类的定义,将super作为cls的__index元表即可。
-
给
cls添加一个super属性,并将super设置为cls的__index元表,对上面class函数做出如下扩展local cls = {__className = className, __isClass = true} if type(super) == "table" then if not cls.__super then cls.__super = super end end cls.__index = cls if cls.__super then setmetatable(cls, {__index = cls.__super}) end -
测试代码
local BaseClass = class("BaseClass") function BaseClass:ctor( ... ) print("BaseClass ctor") end function BaseClass:sayName(name) print(string.format("My name is %s", name)) end local ChildClass = class("ChildClass", BaseClass) function ChildClass:ctor( ... ) self.__super:create() print("ChildClass ctor") self:init() end function ChildClass:init( ... ) self.name = "Hello" end function ChildClass:askName( ... ) self:sayName(self.name) print("What's your name") end local childClass_1 = ChildClass:create() childClass_1:askName() print("childClass_1's name is ", childClass_1.name) print("=========================================") local childClass_2 = ChildClass:create() childClass_2:askName() childClass_1.name = "World" print("childClass_2's name is ", childClass_2.name) print("childClass_1's name is ", childClass_1.name) print("=========================================") local GrandsonClass = class("GrandsonClass", ChildClass) function GrandsonClass:ctor( ... ) self.__super:create() print("GrandsonClass ctor") end local grandsonClass = GrandsonClass:create() grandsonClass.name = "grandsonClass" grandsonClass:askName() -
测试结果
BaseClass ctor ChildClass ctor My name is Hello What's your name childClass_1's name is Hello ========================================= BaseClass ctor ChildClass ctor My name is Hello What's your name childClass_2's name is Hello childClass_1's name is World ========================================= BaseClass ctor ChildClass ctor GrandsonClass ctor My name is grandsonClass What's your name [Finished in 0.0s]
注意:此处实现的是显示调用父类的构造函数,因此在子类的ctor函数中需要先初始化父类self.__super:create()
实现类的多继承
有了上面的基础,实现多继承也是轻而易举的事情了。我们只需要将
__index设置成一个函数,然后遍历父类去用key去检索。当然这样多继承,也会存在一个问题,就是不同父类中有同名方法,或者同名属性,这个时候就和继承顺序与关系。在这里我们按照class("ClassName", SuperA, SuperB, ...)中书写先后顺序作为继承顺序,第一个设置为类的__super
-
多继承实现
class = function (className, ...) if type(className) ~= "string" then error("class name must string type") end local cls = {__className = className, __isClass = true} local supers = {...} for _, super in ipairs(supers) do local superType = type(super) assert(superType == nil or superType == "table" or superType == "function", string.format("create class %s with invalid super class type %s", className, type(super))) if superType == "function" then assert(cls.__create ~= nil, string.format("create class %s with more than one create", className)) cls.__create = super elseif type(super) == "table" then cls.__supers = cls.__supers or {} cls.__supers[#cls.__supers + 1] = super if not cls.__super then cls.__super = super end else error(string.format("create class %s with invalid super class type %s", className, type(super))) end end cls.__index = cls if not cls.__supers or #cls.__supers == 1 then setmetatable(cls, {__index = cls.__super}) else setmetatable(cls, {__index = function (_, key) local supers = cls.__supers for _, super in ipairs(supers) do if super[key] then return super[key] end end end}) end if not cls.ctor then -- default constructor cls.ctor = function ( ... ) end end cls.new = function ( ... ) local instance = {} setmetatable(instance, {__index = cls}) instance.__class = cls instance.ctor(...) return instance end cls.create = function ( ... ) return cls.new(...) end return cls end -
测试
local BaseClass = class("BaseClass") function BaseClass:ctor( ... ) print("BaseClass ctor") end function BaseClass:sayName(name) print(string.format("My name is %s", name)) end local SuperClass = class("SuperClass") function SuperClass:ctor( ... ) print("SuperClass ctor") end function SuperClass:askName( ... ) print(string.format("What's your name")) end local MakeFrinedClass = class("MakeFrinedClass", BaseClass, SuperClass) function MakeFrinedClass:ctor( ... ) self.__super:create() print("MakeFrinedClass ctor") end function MakeFrinedClass:makeFriend( ... ) self:sayName("MakeFrinedClass") self:askName() end local makeFrinedClass = MakeFrinedClass:create() makeFrinedClass:makeFriend() -
测试结果
BaseClass ctor MakeFrinedClass ctor My name is MakeFrinedClass What's your name [Finished in 0.0s]
注意:这里的__super和创建类的时候父类的书写书序有关系,父类如果有同名函数或属性,具体条用那个属性或者函数也和父类书写书序有关系
欢迎讨论和纠正
[Email]huliuworld@yahoo.com







网友评论