C++函数指针和Swift的函数对象

C++函数指针和Swift的函数对象

在C++中学习函数指针式非常痛苦的事情,而在Swift里面学习函数指针则是非常愉快的。

基本语法

一个函数的声明由函数名,参数列表,返回值三个部分组成,在实际应用中,函数本身也可以当作参数,这个时候就是函数指针,函数指针赋予C语言一定的动态能力,C++的很多的功能都是通过函数指针来实现的,不可谓不重要,在Swift等函数式编程语言中,函数更是一等公民,下面是一些简单的例子

typedef int (*OPERATOR)(int, int);//使用typedef简化定义,使代码更易懂
OPERATOR op = max;//不使用typedef的话,可以直接int (*op)(int, int) = max
                  //c++11之后可以auto op = max
op(10,23);
let op: (Int, Int) -> Int = max

上面C++和Swift定义中op是函数指针的名称,指向具体的函数为max,参数是两个Int,返回值也是Int,看起来非常简单吧。

类中的函数指针

请解释一下这段代码:int* (Class::*value[2])(int (*)()),这个value是什么鬼?

C++中的函数指针需要考虑作用域,比如类成员函数,类静态成员函数,C++的成员函数指针和类本身绑定,类型非常复杂,下面代码中fpr的类型为Number (Number::*)(Number),相比普通的函数指针多了一个作用域

class Number {
    int x;
public:
    Number(int value) {
        x = value;
    }
    Number add(Number a){
        return x + a.x;
    }
};
Number (Number::*fpr)(Number) = &Number::add;//复杂的类型
//auto fpr = &Number::add;//c++11
Number num1(10);
(num1.*fpr)(20);//成员函数指针的使用方法

在Swift中函数指针的类型就比较简单,Swift中函数和闭包区别不大,都可以使用同样的类型来表示。

class Number {
    var x:Int
    init(_ v:Int) {
        x = v
    }
    func add(_ b:Number) -> Number {
        return Number(x + b.x)
    }
}
var fpr = Number.add
//fpr的类型是 (Number) -> (Number) -> Number,其中第一个(Number)就是self指针
let num1 = Number(10)
let num2 = Number(20)
let num3 = fpr(num1)(num2)//num1相当于self

在Swift中,所有的函数指针都是一样的,并不区分普通函数指针和成员函数指针,同时,你也没办法在调用的时候感知到这是一个对象成员函数的调用。

构造函数和析构函数

C++标准规定不能对构造函数和析构函数取地址,另外我们也知道这两种函数没有返回值,也没办法定义类型,只能是作为特殊函数对待,网上也有一些hack的方法,通过汇编取这两种函数的地址,和我们讨论的函数指针关系不大,这里就不多讨论了。

在C++里面如果需要构造函数的函数指针,一般会定义一个静态成员函数返回一个对象来完成,比如Number Number::Create(int value)这样的,这样的函数指针也常常出现在工厂方法里面替代直接调用构造函数。

Swift里面构造函数相比其他函数没有什么特殊的地方,记住两步构造和安全检查就差不多了,毕竟创造是比较复杂的事情,所以这里可以直接取构造函数的指针,比如Number.init就是一个类型为(int) -> Number的函数指针,不过Swift的析构函数因为不能直接调用,所以也不能取地址。

上下文

在C++中函数指针是单纯的不带上下文的,在Swift里面不太一样,比如说,在Swift语言中可以对对象的某个函数取指针,接着上面的代码:

var fpr1 = num1.add
let num4 = fpr1(num2)

这里的fpr1的上下文中就包含了num1,好比是在闭包捕获了这个对象,调用fpr1和num1.add是等价的,根据这个特性,可以简化很多操作,假如我们有一个int数组,需要转换成Number数组,用map就可以了,代码是这样的:

let arr2 = arr1.map(Number.init)
//或者
let arr2 = arr1.map {Number($0)}`

然后我们要给所有的元素都加上num2这个对象,这里明显的一点是num1.add(num2)和num2.add(num1)是没有区别的,满足交换律的,所以这个动作可以这么实现:

arr2.map(num2.add)
//或者
arr2.map {$0.add(num2)}

是不是也可以认为num1.add是函数(Number) -> (Number) -> Number的curry,num1是第一个参数,结果是(Number) -> Number.

重载

overload是现代语言中很重要的一个特性,可以给同一个函数名声明不同的参数,C++中要求参数的个数或类型必须有差异,而Swift中允许相同的参数列表和不同的返回值,根据返回值推断具体的函数调用。前面C++代码里面又一个C++11之后的特性,就是auto类型,编译器自动给你生成类型,免得再去面对鬼一样的函数指针声明,不过这个也不是万能的,一旦遇到重载酒不能工作了,还有就是使用函数指针作参数的时候,肯定还是要一丝不苟的把声明给写出来。那么Swift怎么办呢?默认情况下我们使用let和var的声明变量的时候可以不指定类型,交给编译器来推断,在这种无法推断的地方,编译器也无能为力,这里可以使用明确的类型声明来避免二义性,代码:

func magicNumber() -> Int {return 2017}
func magicNumber() -> Float {return 2.20}
let f: () -> Float = magicNumber
f()//顺利得到2.20

总结

Swift在设计的时候有很多函数式编程语言的思想,充分的利用这个特性会让我们的编码效率更高。

C++的函数指针相对比较复杂,而且经常和数组指针等一起混用变得可读性比较差,需要我们去拆分代码。

int* (Class::*value[2])(int (*)())这个搞明白了吗?

typedef Paratype = int (*)();
typedef int* (Class::*Cptr)(ParaType);
Cptr value[2];//这就是你要的value,原来是一个数组
              //数组元素类型是Class类的成员函数指针
              //函数指针的返回值是int*
              //函数的参数类型是Paratype也是一个函数指针,是没有参数返回int的函数指针

就这样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容