函数重载

  出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则称为重载函数(overloaded function)。一定要注意函数重载的两个关键词:形参列表和作用域。

  任何程序有且仅有一个main函数的实例,main函数不能重载。

  对于函数重载来说,它们应该在形参数量和形参类型上有所不同。

  下面论述形参列表和作用域对函数重载的影响。

函数重载与形参列表

  函数重载和函数声明的区别:
  
  如果两个函数声明的返回类型和形参表完全匹配,则将第二个声明视为第一个的重复声明。

  如果两个函数的形参列表相同(参数个数和类型)相同但是返回类型不同,那么第二个函数的声明将会出现编译错误。

  函数不能仅仅基于不同的返回类型而实现重载。

  基于const形参的重载:

  当参数是非引用形参时,形参与const形参的两个同名函数不能构成函数重载。下面的第二个函数只是第一个函数的重复声明。

1 A func(B);
2 A func(const B); // 重复声明

 仅当形参是引用或指针是,形参是否为const才有影响。

A func(B&);
A func(const B&) //基于const引用形参的重载 A func(B*);
A func(const B*); //基于const指针形参的重载

可基于函数的引用形参是指向const对象还是指向非const对象,实现函数重载。将引用形参定义为const来重载函数是合法的,因为编译器可以根据实参是否为const

确定调用哪一个函数。

  如果实参为const对象,那么将调用const引用形参的版本。如果实参为非const对象,非const对象既可以用于初始化const引用,也可以用于初始化非const引用。但是将const引用初始化为非const对象,需要转换,因为非const形参的初始化则是精确匹配。

  对于指针形参也是如出一辙。如果实参是const对象,则调用带有const*类型形参的函数。否则,如果实参不是const对象,将调用带有普通指针形参的对象。

  不能基于指针本身是否为const来实现函数重载。

  

1 A func(B*);
2 A func(B *const); //重复声明,不是重载

  在上述两种情况,都复制了指针,指针本身为const并没有带来区别。

重载与作用域:

 string read();
void print(const string &);
void print(double); //重载print函数
void fooBar(int ival) {
bool read = false; //新作用域:隐藏了外层的read,函数名和变量名都是符号。可以相互屏蔽
string s = read(); //错误:read是一个布尔值,而非函数 //不好的习惯:通常来说,在局部作用域中声明函数不是一个好的选择
void print(int); //新作用域:隐藏了之前的print
print("Value:"); //错误print(const string&)被隐藏了
print(ival); //正确:当前print(int)可见
print(3.14); //正确:调用print(int); print(double)被隐藏了
}

  在函数中声明的名字将屏蔽在全局作用域内声明的同名名字。这个关于变量名字的性质对于函数名同样成立。一般的作用域规则同样适用于重载函数名。如果局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域中声明的同名函数。由此推论,每一个版本的重载函数都应在同一个作用域中声明。在局部作用域中,编译器首先寻找被调用函数的名字。一旦知道到该名字,编译器就不再继续检查这个名字是否咋外层作用域中存在,编译器将认同找到的这个声明即是程序需要调用的函数,余下的工作只是检查名字的使用是否有效。

  当编译器处理调用read的请求时找到的是定义在局部作用域中的read。这个名字是布尔变量,而我们显然无法调用一个布尔值,因此该语句非法。

  当调用print函数的过程类似。在fooBar内声明的print(int)隐藏了之前两个print函数,因此只有一个print函数是可用的:该函数以int值作为参数

  当我们调用print函数时,编译器首先寻找对该函数名的声明,找到的是接受int值那个局部声明。一旦在当前作用域中找到了所需的名字。编译器就会忽略掉外层作用域的同名实体。

  假设我们把print(int)和其他print函数声明放在同一个作用域中,则它将称为另外一种形式重载。此时编译器将能看到所有的三个函数,上述调用结果的处理将会不同:

void print(const string &);
void print(double); //print函数的重载形式
void print(int); //print函数的另一种重载形式 void fooBar2(int ival) {
print("Value: "); //调用print(const string&)
print(ival); //调用print(int)
print(3.14); //调用print(double)
}

函数匹配与实参转换:

  函数重载确定(overloaded resolution, 即函数匹配 function matching) 是将函数调用与重载函数集合中的一个函数相关联的一个过程。

重载函数的三个步骤:

  1. 候选函数

   函数重载确定的第一是确定该调用所考虑的重载函数集合,该集合中的函数为候选函数(candidate function)。候选函数是与被调用的函数同名的函数,并且在调用点上,它的声明可见。

  2. 选择可行函数

   第二步是从候选函数选一个或多个函数,它们能够用调用中指定的实参来调用。因此,选出来的函数称为可行函数(viable function)。可行函数必须满足条件:第一,函数的形参个数与该调用的实参个数相同;第二,每个实参的类型必须与对应的形参的类型匹配,或者可以被隐式转换为对应的形参类型。

  如果没有找到可行函数,则编译器将报告无匹配函数的错误。

  3.寻找最佳匹配

   函数重载确定的第三部就是确定与函数调用使用的市价参数匹配最佳的可行函数。这个过程考虑函数调用中的每一个实参,选择对应形参与之最匹配的一个或多个可行函数。这个所谓的“最佳”的原则是实参类型与形参类型越接近则越匹配。因此,实参类型与形参类型之间的精确类型匹配比需要转换的匹配好。

成员函数可被重载:

  与非成员函数一样,成员函数也可以被重载。

  成员函数只能重载本类的其他成员函数。类的成员函数与普通的非成员函数以及在其他类中声明的函数不相关,也不能重载它们。重载的成员函数和普通函数应用相同的规则:两个重载成员的形参数量和类型不能完全相同。

类中成员函数的重载:

  成员函数的重载:

  类层次中的同名函数来说,有3种关系:重载(overload),覆盖(override)和隐藏(hide)。

  重载的概念相对简单,只有在同一类中的同名成员函数才存在重载关系,主要特点是函数的参数类型和数目有所不同,但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致。另外,重载和成员函数是否是虚函数无关,举例来说:

  

class {
...
virtual int fun();
void fun(int);
void fun(double, double);
static int fun(char);
...
};

上述A类定义中的4个fun函数便是重载关系:

1)相同的范围(在同一个类),父类子类的同名函数是其他关系(覆盖、隐藏)

2)相同的函数名字;

3)不同的参数列表;

4)virtual 关键之可有可无

  基于const的重载:

  基于成员函数是否为const,可以重载一个成员函数:同样地,基于第一个指针形参那是否指向const,可以重载一个函数。const对象只能使用const成员。非const对象可以使用任意成员,但是非const版本是一个更好的匹配。

 class A {
public:
int Func1(int) const;
int Func1(int); //基于const的重载 //返回类型不同也是可以的
int Func2() const;
double Func2(); //正确,可以运行。
};

这篇文章:http://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html较好地讲解了函数重载的底层实现

参考资料:

  1. 《C++ Primer》(第五版)  电子工业出版社

 

【C++】C++函数重载的总结的更多相关文章

  1. 【C++】多态性(函数重载与虚函数)

    多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...

  2. Javascript函数重载,存在呢—还是存在呢?

    1.What's is 函数重载? );//Here is int 10 print("ten");//Here is string ten } 可以发现在C++中会根据参数的类型 ...

  3. javascript 函数重载 overloading

    函数重载 https://en.wikipedia.org/wiki/Function_overloading In some programming languages, function over ...

  4. 01-C#入门(函数重载、委托)

    函数的重载 相对委托,是比较好理解的. 涉及一个概念:函数签名.函数签名包括函数的名称和参数,而函数重载:就是使用相同的名称和不同的参数(参数类型.传递方式[传值或引用])来实现的.而不能声明相同的函 ...

  5. C++函数重载和函数模板

    1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);flo ...

  6. JS魔法堂:函数重载 之 获取变量的数据类型

    Brief 有时我们需要根据入参的数据类型来决定调用哪个函数实现,就是说所谓的函数重载(function overloading).因为JS没有内置函数重载的特性,正好给机会我们思考和实现一套这样的机 ...

  7. 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板

    [源码下载] 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板 作者:webabcd 介绍不可或缺 Windows Native 之 C++ ...

  8. c语言中,既然不支持函数重载,那么printf算怎么回事?在c语言中,它不就是被重载了吗?

    这个问题问的不错.其实printf不是重载,c语言不支持函数重载 这句话是对的.printf函数是通过变长参数表实现的.你可以查看一下printf的函数原型声明.printf函数的实现在不同的机器上是 ...

  9. JavaScript模拟函数重载

    JavaScript是没有函数重载的,但是我们可以通过其他方法来模拟函数重载,如下所示: <!DOCTYPE html> <html> <head> <met ...

  10. C++模板元编程 - 函数重载决议选择工具(不知道起什么好名)完成

    这个还是基于之前实现的那个MultiState,为了实现三种类型“大类”的函数重载决议:所有整数.所有浮点数.字符串,分别将这三种“大类”的数据分配到对应的Converter上. 为此实现了一些方便的 ...

随机推荐

  1. 20155301 《Java程序设计》实验一(Java开发环境的熟悉)实验报告

    20155301 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验内容及步骤 (一)使用JDK编译.运行简单的java程序 命令行下的程序开发 步骤:打开cmd,建立 ...

  2. 从码云把之前的代码git push 回IDEA 对IDEA里的文件进行简单操作

    前情提要:我的IDEA里的项目之前已经和码云连接成功可以上传.但我直接在电脑文件夹里对文件进行重命名.剪切.粘贴等操作之后IDEA对操作后的文件不识别,无奈之下我将码云上之前的代码推回重新新建了项目. ...

  3. 【整理总结】Visual Studio 扩展和更新

    Add New File File Icons C# outline ClaudiaIDE Code alignment CodeMaid Indent Guides Inline Color Pic ...

  4. yaml中的锚点和引用

    项目引入yaml语言来写配置文件,最近发现利用其锚点&和引用*的功能,可以极大减少配置文件中的重复内容,将相同配置内容收敛到锚点处,修改时,只需要修改锚点处的内容,即可在所有引用处生效. ya ...

  5. MySQL 安装 + Windows7

    Window版本 1.下载 http://dev.mysql.com/downloads/mysql/ 2.解压 如果想要让MySQL安装在指定目录,那么就将解压后的文件夹移动到指定目录,如:D:\m ...

  6. Zabbix学习之路(三)之使用SMTP发送邮件报警及定制邮件报警内容

    1.设置邮件报警的思路 (1)设置触发器(Trigger)-->触发后需要执行的动作(Action) 触发器使用逻辑表达式来评估通过 item 获取到得数据是处于哪种状态.在触发器表达式中我们可 ...

  7. springboot+security+JWT实现单点登录

    本次整合实现的目标:1.SSO单点登录2.基于角色和spring security注解的权限控制. 整合过程如下: 1.使用maven构建项目,加入先关依赖,pom.xml如下: <?xml v ...

  8. spring源码-aop源码-5.1

    一.aop的源码部分还是有点复杂的,但是为了更好的理解,我这里会省去很多不必要的逻辑实现过程.主要方向还是更好的理解整体代码的实现过程. 二.说明重点:aop的过程主要过程有两点:第一点,发现正确和适 ...

  9. springboot入门之一:环境搭建

    springboot简介 springboot做为微服务的开发集合框架,有着天然的好处,它不像springmvc那样笨重繁杂,springmvc众多的配置使得开发人员很厌烦,为解决众多的配置带来的烦扰 ...

  10. Jmeter性能测试使用记录

    使用背景 由于最近公司要求对一批接口做性能测试,所以重拾了一些对于Jmeter的使用,现将部分过程做记录,以便以后回溯. 接口参数化 数据参数文件使用了excel保存出的csv文件,dat格式的文件也 ...