Lua面向对象之多重继承、私密性详解_Lua

在Lua中的多重继承和私密性可能用得比较少,也可能只是我个人用得比较少。
本来想偷懒不写这文章的,因为我今天刚买了个漂移板,连起步都还没学会啊,想多学一会。

咳咳,本着坚持不懈、负责到底的态度,我还是决定随便写几句~(小若:随便写几句是几吨意思啊?!)

1.多重继承之在多个类中查找一个字段

我发现这些高(shen)智(jing)商(bing)人群真的很厉害,这种技巧都能想到,很佩服。
其实多重继承没什么特别的,除非两个将要被继承的类有相同的函数名和属性,否则,处理起来很简单。
 
无非就是在多个table中查找某个字段而已,不简单吗?Lua里的继承就是在别人的table里查找自己不存在的字段罢了。

那么,单继承与多重继承的差别也在这里,一个是只查找一个table,另一个是查找两个或以上的table。

我们就先来看看如何从2个或多个table中查找某个字段,如下代码:

复制代码 代码如下:

function search(classes, key)
    for i = 1, #classes do
        local value = classes[i][key];
        if value ~= nil then
            return value;
        end
    end
end
local t1 = {name = "hehe"};
local t2 = {game = "who"};
print(search({t1, t2}, "game"));

这里的classes参数,是一个table,这个table里又存放了多个table,也就是我们想要继承的那些类。

而key就是要查找的字段。

只需要遍历所有的table,判断这个字段是否在某个table里,找到之后,就返回这个值。
我们的测试代码就是从t1、t2中查找game这个字段,t1、t1可以看成是两个类。
输出结果如下:

复制代码 代码如下:

[LUA-print] who

2.多重继承之创建继承多个类的子类

刚刚的search函数很简单吧?别急着开心,那只是预热一下而已,真正创建多重继承的函数比较复杂。

如下代码:

复制代码 代码如下:

function createClass(...)
    local parents = {...};
    local child = {};
  
    -- 设置类的元表
    setmetatable(child, {
        __index = function(table, key)
            return search(parents, key);
        end
    })
  
    -- 给类新增一个new函数,用于创建对象
    function child:new()
        o = {};
        setmetatable(o, child);
        child.__index = child;
        return o;
    end
  
    -- 返回这个继承了多个类的子类
    return child;
end

createClass函数就是用来创建一个继承了多个类的子类,有点小复杂,慢慢分析:

1) 参数是一个可变参数,我们要将多个被继承的类作为参数传递进来
2) parents用于保存这些被继承的类
3) 创建一个新的table——child,它就是我们想要的那个继承了多个类的子类
4) 给child设置元表,并且设置__index元方法,__index元方法可以是一个函数,当它是一个函数时,它的参数就是元表所属的table,以及要查找的字段名。
5) 我们在__index元方法函数里调用search函数,从多个父类中查找所需的字段。于是,当调用child的某个函数时,就会从各个父类中查找,这已经完成了继承的工作了。
6) 接下来就是我们所熟悉的new函数,用来创建child的子类,实现方式和上一篇所说的是一样 ,如果你忘记了,可以看看这篇文章:http://www.jb51.net/article/55168.htm
7) 最后返回child,一切都完成了。

看似很复杂,其实还是对__index的应用而已。

我们赶紧来测试一下吧,如下代码:

复制代码 代码如下:

    --一个精灵类
    TSprite = {}
    function TSprite:hello()
        print("谁跟你hello!");
    end
  
    function TSprite:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end
  
    -- 一个子弹类
    TBullet = {}
    function TBullet:fire()
        print("别动,再动我就瞄不准了!");
    end
    function TBullet:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end
  
    -- 继承了两个类的子类
    local BulletSprite = createClass(TSprite, TBullet);
  
    -- 子类的对象
    local bSprite = BulletSprite:new();
    bSprite:hello();
    bSprite:fire();

这里创建了两个类:TSprite和TBullet。
然后调用createClass函数,创建一个继承了TSprite和TBullet的子类。
最后创建子类的对象,调用对象的hello和fire函数。
输出结果如下:

复制代码 代码如下:

[LUA-print] 谁跟你hello!
[LUA-print] 别动,再动我就瞄不准了!

怎么样?很简单吧~

3.类的私密性

这里来说一个和多重继承无关的技巧,那就是私密性。

对于Java、C++等语言,我们都很熟悉,public、private、protected等关键词。
这些关键词让封装成为了可能。
 
然后,Lua里是没有私密这种说法的,类也是一个table,table的所有字段都是可以调用的,并没有说哪些是公有的,哪些是私有的。

如果有某些函数和属性不希望被外部调用,那么,也可以,不过这种实现方式看起来很别扭:

复制代码 代码如下:

function createTSprite()
    local self = {name = "benmutou"};
    local function myBus()
        print("myBus是我自己的函数,你不能直接调用");
    end
    local function myGame()
        print("myGame是我自己的函数,你不能直接调用");
    end
    local function hello()
        print("hello:");
        myBus();
    end
    local function hi()
        print("hi:");
        myGame();
    end
  
    local function setName(newName)
        self.name = newName;
    end
  
    return {hello = hello, hi = hi, setName = setName};
end

我们已经不需要用到冒号来定义函数了,这个类的name、myBus、myGame都是不希望给外部直接调用的。

调用createTSprite函数后,会返回一个新的table,这个table仅仅存放了一些字段,这些字段就是能够被外部直接调用的函数或者是属性。

来看看测试代码:

复制代码 代码如下:

    local sp = createTSprite();
    sp.hello();
    sp.hi();

输出结果如下:

复制代码 代码如下:

[LUA-print] hello:
[LUA-print] myBus是我自己的函数,你不能直接调用
[LUA-print] hi:
[LUA-print] myGame是我自己的函数,你不能直接调用

这样,我们创建的对象就只能使用hello、hi、setName函数。

而其他的name、myBus、myGame只能通过这几个能使用的函数去调用,而不能直接调用。
这样就能完成私密性了。
 
不过,我个人有点迷糊,因为这已经不太像一个类的样子了。

4.结束

好了,关于面向对象的内容,暂时介绍到这里。
可能介绍的都比较基础,目的是为了巩固Lua基础。

时间: 2024-11-08 23:49:19

Lua面向对象之多重继承、私密性详解_Lua的相关文章

lua中赋值类型代码详解_Lua

我们来看看lua vm在解析下面源码并生成bytecode时的整个过程: foo = "bar" local a, b = "a", "b" foo = a 首先我们先使用ChunkySpy这个工具来看看vm最终会具体生成什么样的vm instructions 在这里,开头为[数字]的行是vm真正生成的字节码,我们看到一共生成了六行字节码.首先loadk将常量表中下标为1的常量即"bar"赋给寄存器0:然后setglobal将

Lua中table的遍历详解_Lua

当我在工作中使用lua进行开发时,发现在lua中有4种方式遍历一个table,当然,从本质上来说其实都一样,只是形式不同,这四种方式分别是: 复制代码 代码如下: for key, value in pairs(tbtest) do      XXX  end   for key, value in ipairs(tbtest) do      XXX  end   for i=1, #(tbtest) do      XXX  end   for i=1, table.maxn(tbtest)

Lua中的__index方法详解_Lua

当我们访问一个表的不存在的域,返回结果为nil,这是正确的,但并不一定正确.实际上,这种访问触发lua解释器去查找__index metamethod:如果不存在,返回结果为nil:如果存在则由__index metamethod返回结果. 这个例子的原型是一种继承.假设我们想创建一些表来描述窗口.每一个表必须描述窗口的一些参数,比如:位置,大小,颜色风格等等.所有的这些参数都有默认的值,当我们想要创建窗口的时候只需要给出非默认值的参数即可创建我们需要的窗口.第一种方法是,实现一个表的构造器,对

Lua中的协同程序详解_Lua

前言 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行.就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停. 协同程序基础 Lua将所有关于协同程序的函数放置在一个名为"coroutine"的table中.函数c

Lua中的逻辑运算符使用详解_Lua

下表列出了所有的Lua语言支持的逻辑运算符.假设变量A持有true,而变量B持有false:  示例 试试下面的例子就明白了所有的Lua编程语言提供的逻辑运算符: 复制代码 代码如下: a = 5 b = 20 if ( a and b ) then    print("Line 1 - Condition is true" ) end if ( a or b ) then    print("Line 2 - Condition is true" ) end --

Lua中的逻辑运算符使用详解

  这篇文章主要介绍了Lua中的逻辑运算符使用详解,是Lua入门学习中的基础知识,需要的朋友可以参考下 下表列出了所有的Lua语言支持的逻辑运算符.假设变量A持有true,而变量B持有false: 示例 试试下面的例子就明白了所有的Lua编程语言提供的逻辑运算符: 代码如下: a = 5 b = 20 if ( a and b ) then print("Line 1 - Condition is true" ) end if ( a or b ) then print("L

Lua中的面向对象编程详解_Lua

简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 复制代码 代码如下: local tb1 = {a = 1, b = 2} local tb2 = {a = 1, b = 2} local tb3 = tb1   if tb1 == tb2 then      print("tb1 == tb2") else      print("tb1 ~= tb2") end   tb3.a = 3 print(tb1.a) 上述代码会输

Lua包管理工具Luarocks详解

摘要: 1. 什么是Luarocks 2. 源码安装部署Luarocks 3. 注册Luarocks为Lua社区贡献自己的代码 4. Luarocks使用初探 讨论话题 什么是Luarocks 源码安装部署Luarocks 注册Luarocks为Lua社区贡献自己的代码 Luarocks使用初探 什么是Luarocks Luarocks是一个Lua包管理器,基于Lua语言开发,提供一个命令行的方式来管理Lua包依赖.安装第三方Lua包等,社区比较流行的包管理器之一,另还有一个LuaDist,Lu

深入理解Android组件间通信机制对面向对象特性的影响详解_Android

组件的特点对于Android的四大组件Activity, Service, ContentProvider和Service,不能有Setter和Getter,也不能给组件添加接口.原因是组件都是给系统框架调用的,开发者只能实现其规定的回调接口,组件的创建与销毁都是由系统框架控制的,开发者不能强行干预,更没有办法获取组件的对象.比如Activity,Service,BroadcastReceiver,你没有办法去创建一个Activity,Service或BroadcastReceiver,然后像使