lua中没有类的概念,一般所说的类其实就是一个table实现的。关于lua类有两种实现方式
第一种是在cocos2d-x引擎目录下图示文件
function clone(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then--查询是否已复制过该对象
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for key, value in pairs(object) do
new_table[_copy(key)] = _copy(value)--递归复制
end
--同时复制lua元表
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
--Create an class.
function class(classname, super)
local superType = type(super)
local cls
--如果父类既不是函数也不是table则说明父类为空
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
--如果父类的类型是函数或者是C对象
if superType == "function" or (super and super.__ctype == 1) then
-- inherited from native C++ Object
cls = {}
--如果父类是表则复制成员并且设置这个类的继承信息
--如果是函数类型则设置构造方法并且设置ctor函数
if superType == "table" then
-- copy fields from super
for k,v in pairs(super) do cls[k] = v end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
end
--设置类型的名称
cls.ctor = function() end
cls.__cname = classname
cls.__ctype = 1
--定义该类型创建实例的函数为基类的构造函数后复制到子类实例
--并且调用子数的ctor方法
function cls.new(...)
local instance = cls.__create(...)--调用基类构造函数
-- copy fields from class to native object
for k,v in pairs(cls) do instance[k] = v end
instance.class = cls
instance:ctor(...)
return instance
end
else
--如果是继承自普通的lua表,则设置一下原型,并且构造实例后也会调用ctor方法
-- inherited from Lua Object
if super then
cls = clone(super)
cls.super = super
else
cls = {ctor = function() end}
end
cls.__cname = classname
cls.__ctype = 2 -- lua 1表示继承自C++对象;2表示继承自lua表对象
cls.__index = cls
function cls.new(...)
local instance = setmetatable({}, cls)
instance.class = cls
instance:ctor(...)
return instance
end
end
return cls
end
通过阅读上述代码可以看出,如果是继承自c++,则无需我们手动调用基类构造函数,如果是继承Lua表,则需要手动调用构造函数,例如:
/定义名为 Shape 的基础类
local Shape = class("Shape")
//ctor() 是类的构造函数,在调用 Shape.new() 创建 Shape 对象实例时会自动执行
function Shape:ctor(shapeName)
self.shapeName = shapeName
printf("Shape:ctor(%s)", self.shapeName)
end
//为 Shape 定义个名为 draw() 的方法
function Shape:draw()
printf("draw %s", self.shapeName)
end
// Circle 是 Shape 的继承类
local Circle = class("Circle", Shape)
function Circle:ctor()
-- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
-- 类名.super 可以访问指定类的父类
Circle.super.ctor(self, "circle")
self.radius = 100
end
function Circle:setRadius(radius)
self.radius = radius
end
// 覆盖父类的同名方法
function Circle:draw()
printf("draw %s, raidus = %0.2f", self.shapeName, self.raidus)
end
可以看到Circle类的构造函数里调用了基类的构造函数,但是这样使用显得代码不美观,也不方便使用,有没有更好的使用办法呢?答案是有的,这里我结合网上众多资料以及个人理解做一下总结:
第一种方案:
我们可以将调用基类的函数封装出来,如下:
function super(o,...)
--if (o and o.super and o.super.ctor) then
o.super.ctor(o,...)
--end
end
这样在调用的时候直接传进来参数就可以了,不过还是要手动调用
第二种方案:
结合class类的实现,我们在创建类的时候可以这样写
class函数第二个参数我们直接传入一个函数,按照程序原意中继承c++的流程执行,最后也能实现
第三种方案:
反复斟酌class类实现,可以发现,当我们从c++继承时能够自动调用构造函数,当从lua继承时能不能也自动实行构造函数呢,经过摸索,发现利用元表确实可以实现,以下是我的做法
function class(classname, super)
local superType = type(super)
local cls
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
if superType == "function" or (super and super.__ctype == 1) then
print("--inherited from native C++ Object or create function:" .. classname)
-- inherited from native C++ Object
cls = {}
if superType == "table" then
-- copy fields from super
for k, v in pairs(super) do
cls[k] = v
end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
end
cls.ctor = function()
end
cls.__cname = classname
cls.__ctype = 1
function cls.new(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k, v in pairs(cls) do
instance[k] = v
end
instance.class = cls
instance:ctor(...)
return instance
end
else
print("-- inherited from Lua Object:" .. classname)
-- inherited from Lua Object
if super then
cls = clone(super)
cls.super = super
else
cls = { ctor = function()end }
end
cls.__cname = classname
cls.__ctype = 2 -- lua
cls.__index = cls
function cls.new(...)
local instance = {}
if(cls.super) then
instance = cls.super:new(...)
end
setmetatable(instance, cls)
for k, v in pairs(cls) do
instance[k] = v
end
instance.class = cls
instance:ctor(...)
return instance
end
end
_G[classname] = cls;
package.loaded[classname] = cls
setmetatable(cls, {__index = _G});
setfenv(1, cls)
return cls
end
做法也是比较简单。创建实例的时候判断有没有基类,有的话调用构造函数,并设置基类对象元表为子类对象即可完美实现,之后我们创建类时可以直接这样传入基类名字即可
第二种类的实现方式是从网上看到的一位大神写的,代码如下:
这种从概念上实现面向对象的方法做到以下几点:
(1)有类定义和对象的概念,类定义通过new来创建对象,并且同时调用自己的构造函数
(2)子类可以访问基类的成员函数
(3)类定义不能够调用函数(除了new之外),只有对象才能调用函数
(4)构造函数调用有和c++一样的层级关系,先调用父类的构造函数,再调用子类的构造函数
--lua面向对象:概念意义上的实现
local _class={}
function class(super)
local class_type={}
--注意:因为重载了__newindex函数, 所以ctor不要定义为nil
class_type.ctor=false
class_type.super=super
class_type.new=function(...)
local obj={}
--下面的块只做了一件事:依次从父类到当前子类调用构造函数ctor
do
local create
create = function(c,...)
if c.super then
create(c.super,...)
end
if c.ctor then
c.ctor(obj,...)
end
end
create(class_type,...)
end
setmetatable(obj,{ __index=_class[class_type] })
return obj
end
--新加成员:防止定义类调用函数
local vtbl={}
_class[class_type]=vtbl
setmetatable(class_type,{__newindex=
function(t,k,v)
vtbl[k]=v
end
})
--只有定义类修改了__newindex
--vbtl只属于定义类
--new出来的对象共享所有定义类的引用,但独享自己新增加的成员变量
if super then
setmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
end
return class_type
end
使用方法;
base_type=class() -- 定义一个基类 base_type
function base_type:ctor(x) -- 定义 base_type 的构造函数
print("base_type ctor")
self.x=x
end
function base_type:print_x() -- 定义一个成员函数 base_type:print_x
print(self.x)
end
function base_type:hello() -- 定义另一个成员函数 base_type:hello
print("hello base_type")
end
----以上是基本的 class 定义的语法,完全兼容 lua 的编程习惯。我增加了一个叫做 ctor 的词,作为构----造函数的名字。
----下面看看怎样继承:
test=class(base_type) -- 定义一个类 test 继承于 base_type
function test:ctor() -- 定义 test 的构造函数
print("test ctor")
end
function test:hello() -- 重载 base_type:hello 为 test:hello
print("hello test")
end
--现在可以试一下了:
a=test.new(1) -- 输出两行,base_type ctor 和 test ctor 。这个对象被正确的构造了。
a:print_x() -- 输出 1 ,这个是基类 base_type 中的成员函数。
a:hello() -- 输出 hello test ,这个函数被重载了
说明几点:
(1)只有定义类修改了__newindex
(2)vbtl只属于定义类
(3)new出来的对象共享所有定义类的引用,但独享自己新增加的成员变量
有点:
(1)概念上更加清晰,熟悉c++面向对象的很容易了解这个继承的关系
(2)写法上感觉很牛逼,做到了定义不能调用函数这一点
(3)共享函数引用
缺点:
(1)概念上清晰的成本是要更多的时间去理解
(2)虽然做到了c++类定义和对象上的概念区别,但是还是有多东西没有实现
(3)对象也可以定义自己的函数,这一点就直接打破了区分定义和对象的本源,但是价值还是有的
(4)所有new出来对象共享类定义的引用对象,包括不需要复用的函数和table。由此多个对象共享一个定义的table很是个问题!
* 针对(4),可以通过实现定义的init函数,在init函数给不同的对象初始化不同的数据,即使是table!
从实现上可以看到,在new一个对象的时候,没有返回之前是没有设置元表的,因此做到了类定义不能调用函数,不过这种写法有利有弊吧,如果单纯的实现一个功能的时候还是很不错的做法,程序耦合度会很低,这里给出我的使用例子,可以帮助理解
base_type=class() -- 定义一个基类 base_type
function base_type:ctor(x) -- 定义 base_type 的构造函数
print("base_type ctor")
self.x=x
end
function base_type:print_x() -- 定义一个成员函数 base_type:print_x
print(self.x)
self.hello()
end
function base_type:init()
print('==================')
end
function base_type:hello() -- 定义另一个成员函数 base_type:hello
print("hello base_type")
end
输出如下:
k name = print_x
k name = init
k name = hello
base_type ctor
==================
相信都能看懂!
参考:
http://www.cnblogs.com/pk-run/p/4248095.html