LUA中的OOP(2) --- 单继承

来源:互联网 发布:千岛湖惨案 知乎 编辑:程序博客网 时间:2024/05/15 17:42

其实单继承是前几天看的了,但是因为比较忙再加上今天下午摆弄了半天C#,所以一直没有总结。

前面说过lua本身只是一个脚本语言,在它上面玩OOP其实需要深入语言,利用语言提供的机制来实现OOP的机制。这次来看看针对OOP中单继承机制的一个实现方案,这个是根据《lua中文手册》上单继承那部分文章演化而来,我觉得书上的办法虽然看着很灵活但是却不够严格,或者说在语义上不够严谨,所以我做了一些改进,这个方案中我尽量靠近高级语言描述OOP时的文法,大家看完可以体会体会。

结合LUA自身的特点,在这个方案中,我定义了3个函数作为对OO本身描述的原语,分别是: CreateObject用于从指定的原型对象中生成一个新的对象实例;Inherit用于让子原型对象继承指定的父原型对象;Inheritable用于声明某个原型对象是可被继承的。单继承的实现就依靠在定义 原型对象时使用这些原语来达到目的。

<-------------Code Begin------------->


--[[

下面我们先来看3个原语的实现
]]-
-- 传递原型对象和待创建对象,返回新创建的对应类型的对象
function CreateObject(proto_type, newobj)
newobj = newobj or {};
setmetatable(newobj, proto_type);
return newobj;
end

--让child原型对象继承base原型对象
function Inherit(child, base)
setmetatable(child, base)
end

--使得一个原型对象具备"可被继承性"
function Inheritable(proto_type)
proto_type.__index = proto_type


--为proto_type的metatable添加写保护,只允许读取metatable而不许设置,保证继承链不被破坏
proto_type.__metatable = proto_type
end


--首先定义human类的原型
do

local function __print_age(self)
print(string.format("human age = %d", self.age))
end


local function __set_age(self, value)
self.age = value;
end


local function __get_age(self)
return self.agel;
end


human = {
age = 0,
set_age = __set_age,
print_age = __print_age,
get_age = __get_age,
};
--在这里用Inheritable原语声明human原型对象是可以被继承的
Inheritable(human)

end



--然后定义继承者Woman类的原型
do


local function __print_age(self)
print(string.format("woman age = %d", self.age))
end


woman = {
print_age = __print_age,
};
--在这里用Inheritable声明woman原型对象是可以被继承的,在我们这个例子中是否使用这个原语对能否继承其他原型对象并无

--影响。
Inheritable(woman);

--这一步是关键,使用Inherit原语,声明woman原型对象将会继承human原型对象,只要human原型对象使用过

--过Inheritable原语声明自己是可被继承的,那么这里只要用Inherit()原语即可完成继承。
Inherit(woman, human);

end

-- 最后我们来看测试代码,用CreateObject()原语为woman原型对象创建两个新实例对象
newobj0 = CreateObject(woman, {age = 25});
newobj1 = CreateObject(woman, {age = 24});


-- 运行下面的代码可以看到, newobj0和newobj1的属性相互不冲突,是两个完全独立的对象,同时也都继承了

--父类human的方法和属性,特别的,如果各位在上面woman类的定义里注释掉 print_age = __print_age 这句,

--就会发现这个继承本身就带有了一定虚函数的性质(这么说其实尚不严格),允许子类重新实现父类中的成员方法。
newobj1:print_age();
newobj0:print_age();

newobj0:set_age(15);

newobj1:print_age();
newobj0:print_age();

<-------------Code End------------->


原理:很简单,还是靠metatable。Inheritable和Inherit原语都是针对原型对象的metatable在做手脚。Inheritable原语会为原型对象增加__index成员并令

其指向自身,Inherit原语会让子原型对象的metatable指向父类,联合这两点就能看出,当在子类中查找某个不存在成员时会自动去

其父类中查找(因为设置了metatable指向父类,而父类的__index指向其自身)。更进一步的使用递归归纳法可以证得这2个继承原语的组合对任意深度的单继承均有效。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 邮箱里的附件过期了怎么办 邮箱中附件过期了怎么办 扣扣邮箱附件过期怎么办 公司网页版邮箱进不去了怎么办 农行客户端密码忘记了怎么办 中国银行客户端密码忘记了怎么办 建行客户端登录密码忘记了怎么办 中国移动客户端密码忘记了怎么办 再歪一点授权码绑定怎么办 网易邮箱号忘了怎么办 忘记支付宝账号和密码怎么办 支付宝账号密码忘了怎么办 发邮箱文件超2g怎么办 报考计算机二级邮箱不存在怎么办 苹果邮箱登录要imap密码怎么办 注销微信支付后怎么办 手机卡注销后支付宝怎么办 12306手机邮箱都换了怎么办 网易手机邮箱手机换了怎么办 崩坏3号被盗了怎么办 qq账号被永久冻结了怎么办 淘宝账号被永久冻结了怎么办 qq账号被永久冻结怎么办 多多理财账号冻结了怎么办 苹果id安全问题忘记了怎么办 网易邮箱帐号忘了怎么办 网易邮箱密码忘记了怎么办 网易邮箱密码忘了怎么办 网易邮箱忘记邮箱账号怎么办 崩坏3三无号被盗怎么办 qq邮箱给58占用怎么办 支付宝邮箱被占用怎么办 苹果手机下载不了qq怎么办 附件预览时发生错误怎么办 手机下载的压缩包打不开怎么办 邮箱提示中转站剩余容量不足怎么办 手机邮箱密码忘记了怎么办 垃圾邮件被系统删除了怎么办 邮箱里的邮件下载不了怎么办 qq邮箱下载不了文件怎么办 苹果手机忘记邮箱密码怎么办