Lua的面向对象——类和继承

本文转载于:http://www.benmutou.com/archives/1791

终于来了,在Lua中的面向对象编程,相信目前学习Lua的大部分人都是为了开发手机网游吧。
而且基本都是奔着脚本语言的热更新特性去的,所以全脚本开发变得十分流行。

对于普及不太广的Lua(相对于C++、Java等主流语言),需要短时间上手开发游戏,对新手而言不算简单。
所以大家才更习惯于继续用面向对象思想去折腾Lua吧~

好了,不唠叨了,我最不喜欢唠叨了。(小若:是是是,你一点都不唠叨,赶紧开讲!)

1.类的对象

至于如何创建一个类,大家已经很清楚了,就是一个table而已。

那么,要使用这个类去创建多个对象,又如何实现呢?

使用元表和元方法即可。

如下代码:

 TSprite = {
        x = 0,
        y = 0,
    }
    function TSprite:setPosition(x, y)
        self.x = x;
        self.y = y;
    end

    function TSprite:new()
        o = {}
        setmetatable(o, {__index = self});
        return o;
    end

    local who1 = TSprite:new();
    local who2 = TSprite:new();
    who1:setPosition(1, 2);
    who2:setPosition(44, 6);
    print("who1坐标(" .. who1.x .. "," .. who1.y .. ")");
    print("who2坐标(" .. who2.x .. "," .. who2.y .. ")");

留意TSprite的new函数,函数里创建了一个新的table,并且给新的table设置一个元表,这个元表的__index元方法就是TSprite本身,最后返回这个新的table。

于是,所有通过new生成的新table,都可以使用TSprite的函数和各个字段属性(因为__index的值是TSprite)。

因此,我们利用new函数创建了who1和who2,并且调用它们的setPosition函数,最后,who1和who2的x、y值都是不同的。

这就是类的对象了。

2.类对象的__index都是同一个TSprite,为什么x、y值可以不相同?

不知道大家有没有这样一个疑惑,那就是,为什么who1和who2的x、y是不一样的,它们最终调用的不是setPosition函数么?调用self.x时最终不是调用了TSprite的x值么?

这里是会有点混乱,理一理就没问题了:

1). 当who1里不存在setPosition时,回去__index元方法里查找,于是,会找到TSprite的setPosition函数

2). 在setPosition函数里,使用了self.x = x,此时的self就是who1,who1中是不存在x字段的,所以,如果我们要打印self.x的值,则其实是打印了TSprite的x值

3). 但是,注意,但是来了。__index元方法是用于调用的,而不是用于赋值的,因此,self.x = x这句话,其实只是给who1这个table的x字段赋值了,who1本身不存在x字段,此时给它赋值了,于是who1存在了x字段,以后who1都不会再去TSprite里查找x字段了。

4). 因此,对who1和who2的x、y字段进行赋值操作时,是完全不会影响到TSprite的。

3.节省资源——使用TSprite作为元表

我们再仔细观察一下new函数,我们在给新table设置元表的时候,是重新创建了一个元表的:setmetatable(o, {__index = self});

这么做的话,每次调用new函数创建一个新对象时,都会产生一个新的元表,虽然这开支似乎可以忽略,但,拥有强迫症的你,一定很喜欢下面的代码:

function TSprite:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end

在这段新的new函数里,使用self作为元表,然后又使用self作为__index的值。

这么一看,有点绕不过来,我就喜欢大家绕不过来,这样我又可以唠叨了:

1). 调用new函数时,self其实就是TSprite本身,这里完全可以用TSprite代替,不过,为了给以后做铺垫,这里还是使用self吧。

2). self.__index = self,不要被这句代码吓到了,其实还是那么一回事,设置元表的__index元方法,这里就 相当于TSprite.__index = TSprite。

3). TSprite自己作为__index的值没问题么?确实没问题,TSprite也是一个table,table可以作为元表,元表可以有__index元方法,这丝毫没有英雄。

4). 于是,通过这个小技巧,我们就避免了每次调用new函数时都额外创建一个新的元表了。

4.富二代什么的我才不喜欢——继承

我们总是笑话富二代,但谁的内心深处不希望自己是一个富二代呢~

像我这种立志靠自己成为富一代的人,可不多了~(小若:啊我呸~!)

那么,在Lua里如何实现继承呢?很简单,但是需要认真思考,如下代码:

TSprite = {
        x = 0,
        y = 0,
    }
    function TSprite:setPosition(x, y)
        self.x = x;
        self.y = y;
    end

    function TSprite:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end

    local MoneySprite = TSprite:new();
    function MoneySprite:setPosition(x, y)
        print("呵呵,我是富二代,根本不需要改变。");
    end

TSprite仍然没变,但是,我们看看MoneySprite,按之前的理解,它是TSprite的一个对象。

只是,“对象”这称呼是我们自己定的,实际上它还是一个table而已。

此时,我们修改了MoneySprite的setPosition函数,于是,调用MoneySprite的setPosition函数时,与TSprite无关了。

但,这不是重点,重点是接下来的代码:

 local who = MoneySprite:new();
    who:setPosition(44, 6);

    print("who坐标(" .. who.x .. "," .. who.y .. ")");

我们再次调用MoneySprite的new函数创建了一个新对象。

这又是什么情况呢?关键是new函数里的代码,此时,new函数里的self是谁?

new函数是由MoneySprite调用的,因此,self就是MoneySprite。

于是新对象的元表就是MoneySprite,元表的__index也是MoneySprite。

因此~!很神奇的,调用who的setPosition函数的时候,其实也是调用了MoneySprite的setPosition函数。

于是,who就是是MoneySprite的对象,而MoneySprite就是TSprite的子类。

来看看输出结果吧:

[LUA-print] 呵呵,我是富二代,根本不需要改变。
[LUA-print] who坐标(0,0)

怎么样?继承的实现方法也很简单吧?

如果对元表、元方法、self比较生疏的话,可能一时间会理解不过来,没关系,多思考一会,或者隔天再回头思考,就会豁然开朗了。

5.结束

不知不觉这个系列的文章已经写了20篇了,真是太出乎我的意料了。

我竟然可以坚持下来,但写文章的效果确实很好,每晚的1个多小时付出也很值得。

起码,我对Lua基础的理解又更加巩固了~

好吧,继续坚持…(小若:所以说啊~!为什么每次都要用省略号,用感叹号不是更能表达你的决心吗…)

时间: 2024-08-02 20:19:43

Lua的面向对象——类和继承的相关文章

Lua面向对象----类、继承、多继承、单例的实现

(本文转载)学习之用,侵权立删! 原文地址   http://blog.csdn.net/y_23k_bug/article/details/19965877?utm_source=tuicool&utm_medium=referral lua面向对象实现: 一个类就像是一个创建对象的模具.有些面向对象语言提供了类的概念,在这些语言中每个对象都是某个特定类的实例.lua则没有类的概念,每个对象只能自定义行为和形态.不过,要在lua中模拟类也并不困难. lua中,面向对象是用元表这个机制来实现.

面向对象 类的继承

/* 面向对象的三大特性:封装 .继承.多态 Dart中的类的继承: 1.子类使用extends关键词来继承父类 2.子类会继承父类里面可见的属性和方法 但是不会继承构造函数 3.子类能复写父类的方法 getter和setter */ class Person { String name='张三'; num age=20; void printInfo() { print("${this.name}---${this.age}"); } }class Web extends Perso

(转载)【笨木头Lua专栏】基础补充20:面向对象——类和继承

终于来了,在Lua中的面向对象编程,相信目前学习Lua的大部分人都是为了开发手机网游吧.而且基本都是奔着脚本语言的热更新特性去的,所以全脚本开发变得十分流行. 对于普及不太广的Lua(相对于C++.Java等主流语言),需要短时间上手开发游戏,对新手而言不算简单.所以大家才更习惯于继续用面向对象思想去折腾Lua吧~ 好了,不唠叨了,我最不喜欢唠叨了.(小若:是是是,你一点都不唠叨,赶紧开讲!) 笨木头花心贡献,哈?花心?不,是用心~ 转载请注明,原文地址:http://www.benmutou.

lua中基类和“继承机制”

基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lua基类和C++基类极为相似,但是lua中却没有继承这一说,更没有所谓的派生类.lua只能通过一种行为(元表)来模拟C++继承这一方法. 元表:lua中提供的元表是用于帮助lua数据变量完成某些非预定义功能的个性化行为,当它做某一种操作,然而self表中却没有定义实现这种操作的方法,那么为了实现这一操

Python 基础之面向对象类的继承与多态

一:继承 定义:一个类除了拥有自身的属性方法之外,还拥有另外一个类的属性和方法继承: 1.单继承 2.多继承子类: 一个类继承了另外一个类,那么这个类是子类(衍生类)父类:一个类继承了另外一个类,被继承的那个类是父类(超类,基类)object 是所有的类的父类1.单继承 #例:class Human():    def eat(self):        print("远古人类打猎,吃猎物") def sleep(self): print("远古人类吃饱了就睡觉")

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

一.简介 Lua是一门非常强大.非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言.但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是一项庞大复杂的工程,如果没有面向对象功能势必会为开发带来一定的不便.不过幸好Lua中有table这样强大的数据结构,利用它再结合元表(metatable),我们便可以很方便地在Lua中模拟出类.继承和多态等面向对象编程具有的特性. 二.前提知识 按照惯例,我们还是先来熟悉一下必要的前提知识,以便方便

Lua的面向对象,封装,继承,多态

概述 我们总所周知对象是由属性和方法组成的,要用lua要描述一个对象,也必然要有这两个特性,属性和方法.lua的基本结构是table,所以Lua的类,其实都是table,因为它可以存储普通的变量又可以存储方法,我们利用table就可以描述一个对象的属性和方法. 对象 其实lua要模拟一个对象,关键就在于__index设置元表索引这块,它主要起到索引失败后该怎么办,如果它指向一张表,那么__index索引失败后,它会到这张表中去查找有没有你指定的函数或成员值,如果有,__index方法被调用时会返

python_way.day7 模块(configparser,xml,shutil,subprocess)、面向对象(上)(创建类,类的构成,函数式编程与面向对象编程的选择,类的继承)

python_way.day7 1.模块 configparser,xml,shutil,subprocess 2.面向对象(上) 创建类,类的构成,函数式编程与面向对象编程的选择,类的继承 1.模块 configparser 用于处理特定格式的文件,其本职上使用open来操作,只能是  [test1] 特定的格式 [test1] k1 = 123 k2 = True [test2] k1 = 123 k2 = v1 文件内容 1.获取 import configparser #打开文件找到文件

面向对象基础(继承类,抽象方法,接口,委托和事件)

1.页面上实现猫叫,狗叫,虎叫 <asp:Button ID="cat" runat="server" Text="猫叫" onclick="cat_Click" /><br/> <asp:Button ID="dog" runat="server" Text="狗叫" onclick="dog_Click" />