local Class = {x=0,y=0}
--设置类的__index为自己,当用此Class作为元表的实例若在自己的属性和方法中找不到,
--将会在其元表Class的元方法键__index对应的元方法Class查找
Class.__index = Class
function Class:new(x,y)
local instance = {} --初始化instance,如果没有这句,那么类所建立的对象如果有一个改变,其他对象都会改变
setmetatable(instance, Class) --与上面的Class.__index = Class对应,都有才能起效
instance.x = x
instance.y = y
return instance
end
function Class:plus()
self.x = self.x + 1
self.y = self.y + 1
end
function Class:test()
print(self.x,self.y)
end
–以上便建立了一个类(作为父类)
–建立子类
local SubClass = {z = 0}
setmetatable(SubClass, Class)--(A)
SubClass.__index = SubClass
function SubClass:new(x,y,z)
local instance = {}
instance = Class:new(x,y)--(B) --将对象自身设定为父类,这个语句相当于其他语言的super ,可以理解为调用父类的构造函数
setmetatable(instance, SubClass) --将实例对象自身元表设定为SubClass类
instance.z= z --新的属性初始化,如果没有将会按照声明=0
return instance
end
--重定义父类的方法,相当于override
function SubClass:test()
print(self.x,self.y,self.z)
end
--定义一个新的方法
function SubClass:go()
self.x = self.x + 10
end
–以上便建立一个子类SubClass,其父类为Class;
–注意:若SubClass去掉(A)(B),将使得SubClass为一个普通的类;
总结:
以上的两个类如何实现了面向对象?
(1)封装:在Lua中的类,其实都是table,因为table既可以存储普通变量又可以存储函数或者另一个table,利用这个特性,我们实现了面向对象的类中的方法、属性(字段)和构造方法
(2)继承:SubClass的instance,如果在SubClass中找不到的属性和方法,将会去其元表Class(父类)的__index中查找,找到即可调用,实现了继承父类特性
(3)多态:由于__index的查找特性,实例会在自己的__index中查找属性和方法,找到即可调用,不会再继续去父类中 查找,即实现了函数覆盖(C++覆盖定义:总与多态绑定在一起,覆盖发生在派生类与基类之间,两个函数必须完全相 同,且都是虚函数)功能,即多态。
继承与多态要归功于table(元表中的__index)的查找机制
local temp = 0
local a = Class:new(1,2) -- 首先实例化父类的对象,并调用父类中的方法
a:plus()
a:test()
a = SubClass:new(3,4,5) -- 然后实例化子类对象
a:plus() -- 子类对象可以访问到父类中的成员和方法(继承)
a:go() -- 子类对象调用子类中的新增方法
a:test() -- 子类对象调用重写的方法(多态)