lua中基类和“继承机制”

基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法。

继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类。

lua基类和C++基类极为相似,但是lua中却没有继承这一说,更没有所谓的派生类。lua只能通过一种行为(元表)来模拟C++继承这一方法。

元表:lua中提供的元表是用于帮助lua数据变量完成某些非预定义功能的个性化行为,当它做某一种操作,然而self表中却没有定义实现这种操作的方法,那么为了实现这一操作便会去元表中找实现这一操作的方法。

如果每一层的元表都定义一种方法指向上一层要“继承”的lua表,这样是不是就和C++继承一样了,有木有!

元方法:C++中的继承不会改变语言的常规行为。但是lua中却提供了一种可以改变table行为的方法,有两种可以改变的table行为:(__index元方法)查询table及( __newindex元方法)修改table中不存在的字段

(1)__index元方法:当对元表中不存在的字段进行访问时,得到的结果为nil。通过定义这个元表的__index,那个访问结果将由这个方法决定。

这个方法也是“继承”父类的方法。

(2)__newindex元方法:当对元表中不存在的字段进行赋值时,解释器会先找到这个元表的__newindex,如果有就调用它,对__newindex指向的表进行赋值操作, 如果没有才对self表进行赋值。

  1 --保存类类型的虚表
  2 local _class = {}
  3
  4 GLOBAL_OBJ_COUNT = {}
  5 ENABLE_OBJ_COUNT = 0
  6
  7 function FindClassName(target, depth)
  8     for key,value in pairs(_G) do
  9         if value == target then
 10             return key
 11         end
 12     end
 13 end
 14
 15 function ClasCountRetain(c)
 16     local key = FindClassName(c)
 17     if GLOBAL_OBJ_COUNT[key] == nil then
 18         GLOBAL_OBJ_COUNT[key] = 1
 19     else
 20         GLOBAL_OBJ_COUNT[key] = GLOBAL_OBJ_COUNT[key] + 1
 21     end
 22 end
 23
 24 function ClasCountRelease(c)
 25     local key = FindClassName(c)
 26     if GLOBAL_OBJ_COUNT[key] == nil then
 27         GLOBAL_OBJ_COUNT[key] = -100000--标识异常
 28     else
 29         GLOBAL_OBJ_COUNT[key] = GLOBAL_OBJ_COUNT[key] - 1
 30     end
 31 end
 32
 33
 34
 35
 36 function PrintLuaClassCount( ... )
 37     print("PrintLuaClassCount.............")
 38     for key,value in pairs(GLOBAL_OBJ_COUNT) do
 39         print("PrintLuaClassCount:"..key..":",value)
 40     end
 41 end
 42
 43
 44 function BaseClass(super)
 45
 46     -- 生成一个类类型
 47     local class_type = {}
 48     -- 在创建对象的时候自动调用
 49     class_type.__init = false
 50     class_type.__delete = false
 51     class_type.super = super
 52
 53     class_type.New = function(...)           --定义New成员方法
 54         -- 生成一个类对象
 55         local obj = {}
 56         obj._class_type = class_type
 57
 58         -- 在初始化之前注册基类方法
 59         setmetatable(obj, { __index = _class[class_type] })
 60
 61         -- 调用初始化方法
 62         do
 63             local create
 64             create = function(c, ...)
 65                 if c.super then
 66                     create(c.super, ...)      --对所有基类都进行init
 67                 end
 68                 if ENABLE_OBJ_COUNT ~= 0 then
 69                     ClasCountRetain(c)
 70                 end
 71                 if c.__init then
 72                     c.__init(obj, ...)
 73                 end
 74             end
 75
 76             create(class_type, ...)
 77         end
 78
 79         -- 注册一个delete方法
 80         obj.DeleteMe = function(self)
 81             local now_super = self._class_type
 82             while now_super ~= nil do
 83                 if ENABLE_OBJ_COUNT ~= 0 then
 84                     ClasCountRelease(now_super)
 85                 end
 86                 if now_super.__delete then
 87                     now_super.__delete(self)        --对所有基类都进行delete
 88                 end
 89                 now_super = now_super.super
 90             end
 91         end
 92
 93         return obj
 94     end
 95
 96     local vtbl = {}
 97     _class[class_type] = vtbl
 98
 99     setmetatable(class_type, {__newindex =
100         function(t,k,v)
101             vtbl[k] = v                      --赋值操作时self找不到的字段则对vtbl表赋值
102         end
103         ,
104         __index = vtbl, --For call parent method
105     })
106
107     if super then
108         setmetatable(vtbl, {__index =       --元表做“继承”操作
109             function(t,k)
110                 local ret = _class[super][k]
111                 return ret
112             end
113         })
114     end
115
116     return class_type
117 end

时间: 2024-10-08 10:24:35

lua中基类和“继承机制”的相关文章

C++中基类的析构函数为什么要用virtual虚析构函数

知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放.假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数.那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏

C++中基类虚析构函数的作用及其原理分析

虚析构函数的理论前提是 执行完子类的析构函数,那么父类的虚构函数必然会被执行. 那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调用子类的虚构函数,导致内存的泄漏. 故: 继承时,要养成的一个好习惯就是,基类析构函数中,加上virtual. 知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual

详解C++中基类与派生类的转换以及虚基类

很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中全部都按原样保留下来了,在派生类外可以调用基类的公用成员函数访问基类的私有成员.因此,公用派生类具有基类的全部功能,所有基类能够实现的功能, 公用派生类都能实现.而非公用派生类(私有或保护派生类)不能实现基类的全部功能(例如在派生类外不能调用基类的公用成员函数访问基类的私有成员).因此,只有公用派生

Android Studio中查看类的继承关系

查看类的继承关系的快捷键F4,在Android Studio常用快捷键这篇文章中,有写了.今天主要是讲一些关于这个快捷键出来的界面的一些配置,这块功能相对偏冷一些,可能很多人都会用不到.但是关于这些配置,android studio中很多都是类似的. 废话不多说,直接上图,如下图,我选中Activity,然后按F4,右边会出现一个和Activity有继承关系的图. 1.先简要分析下图中几个元素: 注:这边说第几个图标是从左到右的顺序来数的 第一个图标:显示所有的继承关系,包括父类,子类 第二个图

关于Python中的类普通继承与super函数继承

关于Python中的类普通继承与super函数继承 1.super只能用于新式类 2.多重继承super可以保公共父类仅被执行一次 一.首先看下普通继承的写法 二.再看看super继承的写法 参考链接:http://blog.csdn.net/lqhbupt/article/details/19631991

【转载】Lua中实现类的原理

原文地址 http://wuzhiwei.net/lua_make_class/ 不错,将metatable讲的很透彻,我终于懂了. ------------------------------------------------------------ Lua中没有类的概念,但我们可以利用Lua本身的语言特性来实现类. 下文将详细的解释在Lua中实现类的原理,涉及到的细节点将拆分出来讲,相信对Lua中实现类的理解有困难的同学将会释疑. 类是什么? 想要实现类,就要知道类到底是什么. 在我看来,

关于Java中基类构造器的调用问题

在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些额外的方法和域.但继承并不只是复制基类的接口.当创建一个导出类对象时,该对象包含了一个基类的子对象,这个子对象与你用基类直接创建的对象是一样的,二者区别在于,后者来自于外部,而基类的子对象是被包裹在导出类对象内部. 这就引发出了一个很重要的问题,对基类子对象的正确初始化也是至关重要的(我们可能在子类的使用基类

c++中基类与派生类中隐含的this指针的分析

先不要看结果,看一下你是否真正了解了this指针? 1 #include<iostream> 2 using namespace std; 3 4 class Parent{ 5 public: 6 int x; 7 Parent *p; 8 public: 9 Parent(){} 10 Parent(int x){ 11 this->x=x; 12 p=this; 13 } 14 virtual void f(){ 15 cout<<"Parent::f()&q

C# 中基类,虚类,抽象类,密封类,接口的区别

在派生类中重写基类中的虚方法使用override: 在派生类中调用基类中的方法似乎用Base.method(); 在派生类中修改基类中的普通方法可以用new 关键字重写: 密封类中的方法都不能再派生类中使用; 抽象类与抽象方法使用abstract关键字,抽象方法不使用花括号{},抽象类中可以有不抽象的方法与属性.也就是抽像类中不全部是抽象方法与属性. 当一个非抽象类继承了抽象类.就必须实现它所有的抽象方法如果只有 一个抽象方法没有实现,那个这个非抽象类必须设置为抽象的.抽象类不能实例化,没有对象