对于不同的语言, 尤其是静态语言和动态语言, 对于函数的定义(即如何看待一个函数)和处理截然不同。具体来说可以分为两类:

1、将函数视为第一类型值, 即函数和其他的对象一样, 都是语言中一个普通的对象类型, 如同基本类型int, string。as和lua作为动态语言都可以归为此类。

2、将函数视为非第一类型值, 即函数本身并不是一种类型的对象, 而仅仅是一个定义, 函数名作为入口地址来使用。c++作为静态语言可以归为此类。

一、对于函数的this对象处理

1、c++中函数的this只对成员函数有效。成员函数指针的声明也与普通函数指针的声明不同, 必须指定类的定义。

例如,一个类的定义如下


class CAnimal
{
public:
void printName();
}

则它的一个成员函数指针可以定义如下:

void (CAnimal::*memberFunc)(void) = &CAnimal::printName;

而要通过成员函数指针来调用一个函数, 则必须通过某个类实例来调用,如下:

CAnimal dog1;
CAnimal dog2;
(dog1.*memberFunc)();  //dog1 (dog2.*memberFunc)();  //dog2

这时候, 编译器会自动将this指向dog对象。

2、as中无论是成员函数还是非成员函数(匿名函数, 也即closer function), 都是可以使用this关键字。区别在于如果用一个Function对象分别指向一个类的实例的成员函数, 则该Function对象在调用时, 无论使用什么方法调用(函数式调用, apply或者call),this对象是不变的, 即初始化时绑定的类实例。而如果用一个Function对象指向一个closer function, 则this指向在调用时显示指定的函数对象。

as要实现1中c++例子的功能, 则需要类似于如下的代码:

public class Animal
{
public function printName(): void;
} //绑定成员函数示例
Animal dog1;
Animal dog2;
var memberFunc: Function = dog1.print;
memberFunc(); //dog1
memberFunc.apply(dog2); //虽然这里显示的指定dog2,但是依然输出dog1. //绑定闭包函数示例
var closerFunc: Function = function(): void
{
this.printName();
};
closerFunc.apply(dog1); //dog1
closerFunc.apply(dog2); //dog2

实际上我个人认为, 在闭包函数中使用this, 是一个相当不好的习惯。因为闭包函数本身是一个临时函数, 不属于任何对象。 如果说要作用于某个对象, 还不如把这个对象设置为函数参数。基于这个观点, 我实在看不出在as3.0里, Function的apply和call中的第一个参数thisArg有任何存在的价值。

3、lua中的self即是this的概念。lua是通过语法糖:定义函数时来自动获取self对象的。 如果是通过一个function对象来调用函数, 则self永远是不固定的, 必须在调用时显示的传入第一个参数作为self。

CAnimal = {};

function CAnimal:new(o)
--省略
end function CAnimal:printName()
print("name: ", self._name);
end local dog1 = CAnimal.new();
local dog2 = CAnimal.new(); local memberFunc = CAnimal.printName; --这里也可以直接写成local memberFunc = dog1.printName; memberFunc(dog1); --dog1
memberFunc(dog2); --dog2

二、关于同一个类不同实例的函数对象或者说函数指针的相等比较

1、C++中的函数并非是一个类型值, 而是一个地址, 并且只能通过函数指针进行存储。所以不存在同一个类不同实例的函数指针比较的说法, 他们的同一个成员函数永远指向同一个地址。

2、as中同一个类不同实例的函数对象是不等的,如:

dog1.printName != dog2.printName;    //true

3、lua的设计实际上是没有类和实例的概念, 而是通过类的原型和类的实例来模拟oo系统。在上面的例子也可以看到, 不同实例的同一个函数实际上是原型的同一个属性。所以可以认为同一个类不同实例的函数对象是相等的, 如:

dog1.printName == dog2.printName;    --true

4、C++、as、lua对于闭包函数的比较是相同的, 同一个闭包函数是相等的, 非同一个闭包函数是不相等的。这里要特别注意理解同一个闭包函数的意义, 即第一次赋值定义, 如:

function getHandler(): Function
{
return function():void
{
//省略
};
}; var handler1: Function = getHandler();
var handler2: Function = handler1;
var handler3: Function = getHandler(); trace(handler1 == handler2); //true;
trace(handler1 == handler3); //false;

三、在c++和lua中实现一套灵活的消息机制

  上面对不同的语言的函数特性进行了较为深入的分析和比较, 接下来为了在以C++为宿主语言(我们也不妨称之内核),以lua为逻辑脚本语言的程序架构中实现一套灵活好用的消息机制, 我们首先将逻辑层面的消息模型表示出来,然后再根据语言特性采用合理的方式来实现这个抽象模型。

  as中的事件模型, 是以IEventDispather为基础的,每一个EventDispather的派生类都可以利用系统已有的机制, 增加事件监听对象以及派发事件。尤其需要注意的是, 显示列表中的对象的事件模型, 被划分为三个阶段:捕获阶段包括从根到事件目标节点之前的最后一个节点的行程,目标阶段仅包括事件目标节点,冒泡阶段包括到显示列表的根的回程上遇到的任何后续节点。如果把as的事件模型看做一个典型的观察者模式, 则每一个EventDispather都是一个被观察的subject, 而他的一个事件监听对象便是一个observer的一个回调接口(这里为什么说是一个回调接口,而不是一个observer。因为一个observer会对一个object注册多个监听接口。而as中Function最方便的地方是不仅确定了回调接口, 而且可以方便的进行相等比较, 还唯一对应一个对象实例。具体可以参考), 用于响应一个特定的事件。

  为as定制的mvc框架robotlegs。()

三种语言(c++、as、lua)中函数的差异性的更多相关文章

  1. java php c# 三种语言的AES加密互转

    java php c# 三种语言的AES加密互转 最近做的项目中有一个领取优惠券的功能,项目是用php写得,不得不佩服,php自带的方法简洁而又方便好用.项目是为平台为其他公司发放优惠券,结果很囧的是 ...

  2. 树的三种DFS策略(前序、中序、后序)遍历

    之前刷leetcode的时候,知道求排列组合都需要深度优先搜索(DFS), 那么前序.中序.后序遍历是什么鬼,一直傻傻的分不清楚.直到后来才知道,原来它们只是DFS的三种不同策略. N = Node( ...

  3. 进程,多进程,进程与程序的区别,程序运行的三种状态,multiprocessing模块中的Process功能,和join函数,和其他属性,僵尸与孤儿进程

    1.进程 什么是进程: 一个正在被运行的程序就称之为进程,是程序具体执行的过程,是一种抽象概念,进程来自操作系统 2.多进程  多个正在运行的程序 在python中实现多线程的方法 from mult ...

  4. GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则

    20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...

  5. 一种C#泛型方法在lua中表示的设计

    在进行lua方法注册的时候, 大多数解决方案直接否定了泛型方法, 因为在lua侧难以表达出泛型, 以及lua的函数重载问题, 函数重载问题可以通过一些特殊方法解决, 而泛型问题是主要问题, 以Unit ...

  6. Hibernate中对象的三种状态以及Session类中saveOrUpdate方法与merge方法的区别

    首先,用一张图说明一个对象,在Hibernate中,在调用了不同方法之后对象所处的不同状态 在Hibernate中,一个对象的状态可以被分为如图所示的三种 Transient:瞬时对象,该对象在数据库 ...

  7. eclipse安装插件的方式 三种:links、eclipse中使用插件安装向导安装、直接copy插件到对应的eclipse目录 MyEclipse10安装SVN插件

    myeclipse安装插件 1.直接将插件copy到myeclipse目录下的dropins目录下(没有目录就新建一个),重启,详细参考 MyEclipse使用总结——MyEclipse10安装SVN ...

  8. ASP.NET Core端点路由中三种让人困惑的路由函数

    早先提及了端点路由app.UseEndpoints, 端点路由强调的是端点和 路由,其核心目的是将 请求落地点与路由寻址方式解耦. 这里面有几个容易混淆的函数 MapControllerRoute M ...

  9. django入门与实践 - 关于升级到django 3.7,三种模板超链接配置(编辑中)

    第一种方法: 在myblog/urls.py模块中: from django.contrib import admin from django.urls import path, include ur ...

随机推荐

  1. 【Java】聊聊常用的摘要算法,比如MD5

    摘要算法的特性 摘要算法的目的的将信息进行简单地摘要,将任意长的信息摘要成固定长的信息.比如MD5,将任意长的信息摘要成128位的摘要. 不可逆的,将报文摘要成一段信息后,无法通过摘要信息还原会报文. ...

  2. PHP判断用户设备是否是移动设备

    摘自http://www.oschina.net/code/snippet_1432190_46913   <?php function isMobile() { // 如果有HTTP_X_WA ...

  3. 逐个后移,匹配符合要求的选项,ie7有bug

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. ASP.NET API盘点

    1.控制只返回JSON一种数据 public class JsonContentNegotiator : IContentNegotiator { private readonly JsonMedia ...

  5. Create XO Checker Game With Oracle Forms

    Created XO Checker game in Oracle Forms and sharing its FMB (source code) for reference so that you ...

  6. 【转】利用Pspice分析放大器环路的稳定性

    文章来源: http://www.21ic.com/app/test/201108/90808.htm 虽然在较低频率下可以较轻松地检查一个简单放大器的稳定性,但评估一个较为复杂的电路是否稳定,难度可 ...

  7. Makefile文件简单整理

    .PHONY:clean main:hello.o gcc -o main hello.c hello.o:hello.c gcc -c hello.c clean: rm -f hello.o ma ...

  8. CUBRID学习笔记 14 dll加载错误

    这个问题通常是缺少文件cascci.dll 或者版本错误 32 64弄错了 C:\Program Files (x86)\Python266>python.exe Python 2.6.6 (r ...

  9. ubuntu下卸载vmware

    直接crl+alt+t打开一个terminal,然后输入sudo vmware-installer --uninstall-product vmware-workstation即可卸载!操作如下图: ...

  10. source命令

    source命令用法: source  文件名作用:在当前bash环境下读取并执行文件中的命令.注:该命令通常用命令“.”来替代.如:source .bash_rc 与 . .bash_rc 是等效的 ...