专栏首页编程珠玑什么是函数重载?

什么是函数重载?

前言

函数重载指的是一个作用域内的几个函数名字相同但是形参列表不同。这些函数执行操作类似,但是接受的形参类型不一样,编译器会根据传递的实参类型选择对应的函数调用。本文将简单介绍C++中的函数重载。

定义重载函数

假设有一个计算图形面积的函数,它可以是计算三角形,圆形或正方形的面积。函数的名字都相同,只是根据传入的图形类型来选择不同的函数来计算面积,程序清单如下:

#include <iostream>
using namespace std;
typedef struct Triangle//定义三角形结构
{
    double high;//高
    double baseLen;//底边长
}Triangle;
typedef struct Circle //定义圆形结构
{
    double radius;//半径
}Circle;
typedef struct Square//定义正方形结构
{
    double sideLen;//边长
}Square;
//函数1.计算三角形面积
double  calcArea(const Triangle&)
{
    cout<<"calcute triangle area"<<endl;
}
//函数2.计算圆形面积
double  calcArea(const Circle&)
{
    cout<<"calcute circle area"<<endl;
    return 0;
}
//函数3,计算三角形面积
double  calcArea(const Square&)
{
    cout<<"calcute square area"<<endl;
}
int main(void)
{
    Triangle triangle;
    Circle circle;
    Square square;
    calcArea(triangle);//调用函数1
    calcArea(circle);//调用函数2
    calcArea(square);//调用函数3
    return 0;
}

可以看到,定义的三个函数名calcArea都相同,只是形参类型不同。当分别传入三角形,圆形和正方形类型时,会调用对应的函数。 运行结果如下:

calcute triangle area                                                                                                                                                                       
calcute circle area                                                                                                                                                                         
calcute square area 

可以看到,当分别传入Triangle ,Circle,Square类型时,分别调用了对应的函数。

为什么要重载

函数重载在一定程序上可以减轻程序员起名字的负担。最常见的一个例子就是构造函数的重载。

class Test
{
   public:
      Test(void);  // 无参构造函数
      Test(int a);//构造函数
      Test(int a,int b);//两个整型参数的构造函数
};

可以看到,类Test的三个构造函数名都为Test。如果没有重载,要实现三个构造函数就可能需要三个不同的构造函数名区分,这也就增加了类的使用者的负担,使用者需要传入不同参数构造对象时,就需要使用不同的构造函数名称。而有函数重载之后,类的使用者可以使用同一个函数名传入不同的参数即可。

当然了,如果单纯地为了减轻起名字的负担而去使用函数重载,而使得函数失去了本来的信息,则是一个不明智的选择。我们可以为那些操作确实极其相似的函数进行重载。

不能重载的情况

以下几种情况下,是不能重载或者说是非法的。

main函数不能重载

这是在C++ 11标准中说明的:

A program shall contain a global function called main, which is the designated start of the program....
This function shall not be overloaded.

试想如果作为用户程序入口函数的main函数被重载了,那么加载的时候该以哪个为入口呢?

只有返回值不同

例如下面两个声明只有返回值不同,函数名和形参都相同:

double calcArea(const Square&);
int calcArea(const Square&);  //非法,仅有返回值不同,不可重载
/*以上声明同时出现会报错*/

试想一下,当你传入Square类型参数,而不去使用返回值时,应该调用上面的哪个函数呢?

形参列表看似不同,实则相同

例如使用typedef给Triangle起了一个“别名”:

typedef Triangle MyTri;
double calcArea(const Triangle&);
double calcArea(const MyTri&);
/*以上声明同时出现会报错*/

上面这种情况的形参看似不一样,本质上来说它们并没有什么不同。

形参名不同

例如:

double calcArea(const Circle &circle );//形参名为circle
double calcArea(const Circle& cir);//形参名为cir
double calcArea(const Circle& );//省略形参名
/*以上声明同时出现会报错*/

这里形参的名字仅仅是起到说明或者记忆的作用,因此对于上面三个声明,它们的形参名可以随意起,但不会影响形参列表的内容。

仅有顶层const的差异

例如:

double calcArea(const Circle);//函数1
double calcArea(Circle);//重复声明了函数1
/*以上声明同时出现会报错*/
double calcArea(Circle* const);//函数2
double calcArea(Circle*);//重复声明了函数2
/*以上声明同时出现会报错*/

但需要特别注意的是,如果形参是指针或引用,是可以通过区分指向大到底是常量对象还是非常量对象来实现函数重载。例如下面的情况是可以实现函数重载的:

double calcArea(const Circle&);//作用于常量引用
double calcArea(Circle&);
/*以上声明同时出现不会报错*/
double calcArea(const Circle*);//作用于常量指针
double calcArea(Circle*);
/*以上声明同时出现不会报错*/

总结

在定义了重载函数后,我们需要以合理的实参进行调用。大多数情况下,我们很容易判断传入的对应实参需要调用哪个函数,但是有些时候却并不那么容易。我们将会在后面的文章中看到如何进行函数匹配

我们对前面的内容做一个总结:

  • 函数重载能够减轻程序员命名的负担,但这不应该以丢失可读性为代价。
  • main函数不能重载。
  • 重载函数的形参在数量或者类型上要有不同。
  • 不能以返回值作为函数重载要素。
  • C语言没有函数重载。

本文分享自微信公众号 - 编程珠玑(shouwangxiansheng),作者:守望先生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 彻底理清重载函数匹配

    前面我们讲到了《什么是函数重载?》,有了函数重载之后,就需要确定某次调用需要选用哪个函数。这个过程可以称之为函数匹配或者重载确定。大多数情况下,我们都很容易能够...

    编程珠玑
  • C语言入坑指南-整型的隐式转换与溢出

    我们知道整型有无符号数和有符号数之分。如果我们对无符号数和有符号数处理不当,就可能造成难以预测的结果,尤其是在作为循环条件的时候,可能导致死循环。整型之间的运算...

    编程珠玑
  • 父进程退出时如何确保子进程退出?

    子进程退出的时候,父进程能够收到子进程退出的信号,便于管理,但是有时候又需要在父进程退出的时候,子进程也退出,该怎么办呢?

    编程珠玑
  • 微信小程序图片使用示例

    王小婷
  • FSLIB.NETWORK 简易使用指南

    阿炬
  • C#如何遍历某个文件夹中的所有子文件和子文件夹(循环递归遍历多层),得到所有的文件名,存储在数组列表中

    响应(调用)代码如上面,比如写在某个事件中。首先是有一个已知的路径,现在要遍历该路径下的所有文件及文件夹,因此定义了一个列表,用于存放遍历到的文件名。

    acoolgiser
  • 使用InstallUtil发布windows服务

       a)ServiceName =”FirstService”;   //设置服务名称

    写代码的猿
  • 移动互联网10年,传奇一直在发生

    一位记者问:“这都是哪请来的托,太敬业了!”工作人员只得实话实说:“都是自己来的,我们也没想到。”

    瑾诺学长
  • HTTP请求头referer

    留言板有个来源的字段,用来获取网页的地址。测试时发现在谷歌Chrome浏览器中,可以正确获取到网址来源,然后用火狐Firefox浏览器,却无法正确获取到网址来源...

    siberiawolf
  • 贝叶斯算法-简易入门

    推论过程:P(A∩B) = P(A|B) * P(B) = P(B|A) * P(A)

    solve

扫码关注云+社区

领取腾讯云代金券