首页 > 代码库 > 初步理解[函数重载]和[运算符重载]·转

初步理解[函数重载]和[运算符重载]·转

作者:黄兢成
链接:https://www.zhihu.com/question/23407045/answer/24543450
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

很多疑问都是想不通那东西具体用于什么地方。


比如我初学 C++ 时,早就知道指针实际就是某个变量的地址,就是不知道具体怎么用。这感觉就仿佛学数学,我知道某定理,也知道某定理的证明是对的,但我就是不知道这东西有什么用。直到学数据结构,接触到链表,才突然明白指针。


所以语法只是初步,更重要的是要想明白遇到什么问题了,才需要有那个语法。之后再进一步,去探究具体实现。


去想想

  • 遇到什么问题?约束条件是什么?
  • 在这约束条件下,那些人是怎么解决的?
  • 怎么去评价那个解决方法?
  • 现在那个约束条件存在不?假如不存在了,是不是有更好的?

重载函数

重载,英文为 overloading,大概就是很多个的意思。

举个例子,我需要个函数取 2 个 int 的最大值。函数接口应该是

    (1) int max(int a, int b); 

那更进一步,我取3个 int 的最大值呢,接口可以定义为

    (2) int max(int a, int b, int c);

函数 (1) 和 (2)的名字是一样的,都叫 max,就只有参数的个数不同。这是函数重载。

那现在,我需要取两个float的最大值呢,接口也可以定义为

    (3) float max(float a, float b);

对比 函数(1) 和 (3),名字也是一样的,参数个数也是一样的。不过参数的类型不同。这也是函数重载。


所以函数重载就是,名字相同,但参数个数不同或者参数类型不同。


够简单吧。


不过,我相信到这里还会似懂非懂的。那我们去设想一下,上面的例子,假如没有重载,也就是函数的名字不可以相同,那会怎么样?


第(1)个函数,还是叫max吧。那第(2)个函数,就不能叫max了。就叫max3吧,因为有3个参数。这样第(1)个函数还是叫max不好吧,就叫max2, 有两个参数,跟max3对应起来。那第(3)个函数怎办。因为是2个浮点。就叫max2f吧。f表示浮点。


那现在 max2, max3, max2f又不统一了。就叫 max2i, max3i, max2f, 吧。那到时 double, long, long long类型,各自有2个参数,或者3个参数。那就出现 max2i, max3i, max2f, max3f, max2l, max3l ......


同一个取最大值的概念。出现了多个不同的名字。似乎不好吧。可能你觉得上面的例子是我作的,真实中应该不至于这样吧。但实际上在 C 语言中,就发生这样的事情。


C 语言就没有函数重载的。下面都是 C 标准库中取绝对值的函数。

    float fabsf(float);
    double fabs(double);
    long double fabsl(long double);
    int  abs(int);
    long labs(long);
    long long llabs(long long);

有了重载和模板(模板这里不说),C++ 中就为 std::abs,只有一个名字。


另一个例子,就是 C 语言写的 OpenGL 接口,下面函数都是定义顶点。

    glVertex4i
    glVertex4s
    glVertex2dv
    glVertex2fv
    glVertex2iv
    glVertex2sv
    glVertex3dv
    glVertex3fv
    glVertex3iv
    glVertex3sv
    glVertex4dv
    glVertex4fv
    glVertex4iv
    glVertex4sv

无重载,同一个概念,弄出这样多名字了。


运算符重载

运算符,就是 + - * / == != 那些符号。运算符重载,也就是可以重新定义那些运算符。


那有什么用呢?举个例子。


Point 表示点。两个点可以相加,相减,判断是否等于....


假如没有运算符重载。需要定义这样的函数。

Point point_add(const Point& a, const Point& b);
Point point_sub(const Point& a, const Point& b);

使用起来,就是。

Point c = point_add(a, b);
Point d = point_sub(c, a);

又加又减,会变成

Point d = point_add(a, point_sub(c, d));

而在 C++ 中重新定义运算符号,可以写出这样的代码

Point c = a + b;
Point d = c - a;
....
Point d = a + (c - d);

对比一下,运算符重载会更易读易写。


运算符重载可以算个语法糖,无这个东西还是可以写代码,不过没有写得那样漂亮自然。当做一件事情很麻烦的时候,通常就偷懒不去做了。


再举个我遇到的例子。最近用到个object-c 库 Masonry。object-c 没有运算符重载,这个库有些代码写起来是这样写的。不用管它的意思。就去感受一下。

make.top.equalTo(superview.top).with.offset(padding.top);
make.left.equalTo(superview.left).with.offset(padding.left);
make.bottom.equalTo(superview.bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.right).with.offset(-padding.right);
.......
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400);

同样的含义,假如有了运算符重载。我相信可以写成这样。

make.top     == superview.top    + padding.top;
make.left    == superview.left   + padding.left;
make.bottom  == superview.bottom - padding.bottom;
make.right   == superview.right  - padding.right;
......
make.width >= @200;
make.width <= @400;

看看代码的美感。功能虽然一样,但是否漂亮,会有根本的不同。


不过要注意。C++有些地方也会写得很丑的,比较多余的。同样问题,不同的语言会有不同的做法。C++中的解决方法,不一定最好的。

初步理解[函数重载]和[运算符重载]·转