写在前面

  • 最近在琢磨“Lua热重载”,在测试中发现我之前对Lua中的面向对象实现有一些理解发生变化,这里记录一下。
  • 本文提到的面向对象实现来自云风

类实现

  • 《Lua程序设计(第4版)》以银行账户存取钱为例,解释了如何实现一个类。从“面向对象的3大特性”角度,它的实现概括如下:

    • 继承:改__index引向自己
    • 多态:不用新建其他类,会自动找到对应方法(多重继承,书上举例是用查找父类方法实现的)
    • 封装:
      • 单方法:将公开的字段和函数放在单独表中;不过这种方式不能“继承”。
      • 对偶:把表当key存起来;可“继承”。
  • 不过《Lua程序设计(第4版)》书上没有完整的可直接拷走的代码,我工作项目用的是toLua,toLua也没有提供Lua类脚本,所以用了云风设计的class代码,如下:
local _class={}

function class(super)
local class_type={}
class_type.ctor=false
class_type.super=super
class_type.new=function(...)
local obj={}
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
}) 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

理解

  • 对比:有对比才能看出云风写的class好在哪,之前我在看LuaFramework_UGUI框架时,它有一个写的很短很简单的LuaClass(如下),拿LuaClass和云风的对比,能看得出来LuaClass在“面向对象的3大特性”上没有实现“多态”和“封装”,LuaClass仅能作为参考,是不能直接搬到正式工程里用的。
--Author : Administrator
--Date : 2014/11/25 --声明,这里声明了类名还有属性,并且给出了属性的初始值。
LuaClass = {x = 0, y = 0} --这句是重定义元表的索引,就是说有了这句,这个才是一个类。
LuaClass.__index = LuaClass --构造体,构造体的名字是随便起的,习惯性改为New()
function LuaClass:New(x, y)
local self = {}; --初始化self,如果没有这句,那么类所建立的对象改变,其他对象都会改变
setmetatable(self, LuaClass); --将self的元表设定为Class
self.x = x;
self.y = y;
return self; --返回自身
end --测试打印方法--
function LuaClass:test()
logWarn("x:>" .. self.x .. " y:>" .. self.y);
end --endregion
  • 回到class,最开始阅读class代码时,我有好些地方没看懂,包括“_class是放什么的”,“class_type为什么要起名叫class_type”等等。最近在琢磨“Lua热重载”时,再次回顾了这里,对以前理解错误的地方或是一知半解的问题有了新回答。以下是我在阅读时冒出的问题和对应回答:

    • _class是什么?——> _class是记录各种类的类型(以下都称为“类-原型”)的词典(如果是我,会起名为_classTypeMap,这样更好懂)。

      • 比如:新建两个类-原型A和B,此时_class中会记有类-原型A和类-原型B。
local A = class()
local B = class()     
    • class()到底做了什么?——> class()其实负责的是创建“类-原型”,而非“类-实例”,这从它最后return的值是class_type可以看出。如果需要创建“类-实例”,就得用new函数。
    • 下面的代码是什么意思?——> vtbl 即value table,setmetatable这里对class_type有写操作,却无读操作,即class_type里的数据是只写属性,即这些数据仅限于类内部使用。
local vtbl={}
_class[class_type]=vtbl setmetatable(class_type,{__newindex=
function(t,k,v)
vtbl[k]=v
end
})

    有需要的话,可以修改,例如下方就是把原来的只写属性改为可读可写属性,即public:

local vtbl = {}
_class[class_type] = vtbl setmetatable(class_type, {
__newindex = function(t,k,v)
vtbl[k] = v
end, __index = vtbl,
})
    • 下面的代码是什么意思?——> 查找自己没有的数据时,如果有父类super,先去_class里找类-原型super的数据,拿该数据覆盖/填充
if super then
setmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
end
  • 根据上面回答,以下是我加了注释的class代码:
-- https://blog.codingnow.com/cloud/LuaOO
-- 类(注释版) -- _class是记录各种类的类型(以下都称为“类-原型”)的词典
-- 比如:local A = class(),local B = class(),则_class中会记有类-原型A和类-原型B
-- 如果是我,会起名为_classTypeMap,这样更好懂
local _class = {} function class(super)
-- 创建的是类-原型class_type,只有用了类-原型的new函数,才能得到类-实例
local class_type = {}
-- 自定义构造函数ctor
class_type.ctor = false
class_type.super = super
class_type.new = function(...)
local obj = {}
do
local create = function(c, super)
if c.super then
create(c.super, ...)
end
if c.ctor then
c.ctor(obj, ...)
end
end
create(class_type, ...)
end
-- 在_class中查找类-类型为class_type的数据
setmetatable(obj, {__index = _class[class_type]})
return obj
end -- vtbl即value table
local vtbl = {}
_class[class_type] = vtbl
-- 对class_type有写操作,却无读操作,即class_type里的数据是只写属性,即这些数据仅限于类内部使用
-- (可见《Lua程序程序设计(第4版)》第21章“面向对象编程”的“对偶”)
setmetatable(class_type,
{
__newindex = function(t, k, v)
vtbl[k] = v
end }) -- 查找自己没有的数据时,如果有父类super,先去_class里找类-原型super的数据,拿该数据覆盖/填充
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

关于Lua中的面向对象实现的更多相关文章

  1. Cocos2d-x 脚本语言Lua中的面向对象

    Cocos2d-x 脚本语言Lua中的面向对象 面向对象不是针对某一门语言,而是一种思想.在面向过程的语言也能够使用面向对象的思想来进行编程. 在Lua中,并没有面向对象的概念存在,没有类的定义和子类 ...

  2. lua中的面向对象编程

    简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 上述代码会输出tb1 ~= tb2.说明两个具有相同值得对象是两个不同的对象,同时在Lua中table是引用类型的 ...

  3. Lua和C++交互 学习记录之九:在Lua中以面向对象的方式使用C++注册的类

    主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3  参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 在 ...

  4. 【转载】【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态

    [游戏开发]在Lua中实现面向对象特性——模拟类.继承.多态   阅读目录 一.简介 二.前提知识 三.Lua中实现类.继承.多态 四.总结 回到顶部 一.简介 Lua是一门非常强大.非常灵活的脚本语 ...

  5. Lua中的面向对象编程详解

    简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 复制代码代码如下: local tb1 = {a = 1, b = 2}local tb2 = {a = 1, b ...

  6. lua 中的面向对象

    lua 是一种脚步语言,语言本身并不具备面向对象的特性. 但是我们依然可以利用语言的特性,模拟出面向对象的特性. 面向对象的特性通常会具备:封装,继承,多态的特性,如何在lua中实现这些特性,最主要的 ...

  7. 【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态

    一.简介 Lua是一门非常强大.非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言.但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是 ...

  8. Lua 中使用面向对象(续)

    上一篇文章给了一个面向对象的方案,美中不足的是没有析构函数 Destructor,那么这一次就给它加上. 既然是析构,那么就是在对象被销毁之前做该做的事情,lua 5.1 的 userdata 可以给 ...

  9. Lua中的userdata

    [话从这里说起] 在我发表<Lua中的类型与值>这篇文章时,就有读者给我留言了,说:你应该好好总结一下Lua中的function和userdata类型.现在是时候总结了.对于functio ...

  10. 9----Lua中的面向对象

    什么是面向对象? 使用对象.类.继承.封装.消息等基本概念来进行程序设计 面向对象最重要的两个概念就是:对象和类 对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位 一个对象由一组属性 ...

随机推荐

  1. onnxruntime源码解析之C接口实现

    onnxruntime的C接口,位置为include/onnxruntime/core/session/onnxruntime_c_api.h. 上述文件包含了C函数的声明,对应的实现在onnxrun ...

  2. js右键生成菜单

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. COM 对象的利用与挖掘4

    作者:Joey@天玄安全实验室 前言 本文在FireEye的研究Hunting COM Objects[1]的基础上,讲述COM对象在IE漏洞.shellcode和Office宏中的利用方式以及如何挖 ...

  4. C语言中return和exit的区别

    转载自:http://jszx.cuit.edu.cn/NewsCont.asp?bm=00&type=888&id=20050 1.exit用于在程序运行的过程中随时结束.终止程序, ...

  5. 理解函数调用_arguments对象作为函数参数的别名

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. redhat7

    systemctl systemctl enable sshd 开机启动某服务 systemctl disable sshd 开机不启动某服务 systemctl is-enabled sshd查看某 ...

  7. Blender2.8 使用笔记

    基本 视口 小键盘/: 隔离 Z:切换线框与实体显示 Ctrl+Alt+Q : 多视图切换 Shift+C:回原点 Shift+鼠标中键 视口平移 Ctrl+上下移动 视口放大缩小 导出FBX 几何数 ...

  8. Carthage 使用介绍

    1.安装 Carthage 安装 brew install carthage 检测当前版本 carthage version 升级至最新版本 brew upgrade carthage 2.如果更新出 ...

  9. JAVA根据时间增加1天

    String time = "2021-12-1"; //指定时间 int day = 30;//指定增加天数 SimpleDateFormat sf = new SimpleDa ...

  10. TypeScript - 配置文件 tsconfig.json

    tsconfig.json 文件 创建两种方式: 1. 直接在根目录新建tsconfig.config.json (配置文件需要自己配置) 2. 执行tsc --init  (会自动创建相关配置) t ...