函数重载

  出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则称为重载函数(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. Hello World 和 模块分解

    Hello World 和 模块分解 在命令行中编译运行HelloWorld public class HelloWorld { public static void main(String[] ar ...

  2. 20145226夏艺华 网络对抗技术EXP8 WEB基础实践

    20145226夏艺华 网络对抗技术EXP8 WEB基础实践 实验问题回答 1.什么是表单? 表单在网页中主要负责数据采集功能.一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CG ...

  3. WPF GDI+字符串绘制成图片(二)

    原文:WPF GDI+字符串绘制成图片(二) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/details/83 ...

  4. PostgreSQL参数学习:random_page_cost

    磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面:PostgreSQL基础知识与基本操作索引页    回到顶级页面:PostgreSQL索引页[作者 高健@博客园  luckyjackgao@g ...

  5. Walle代码发布

    一.概述 Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用!支持git.svn版本管理,支持各种web代码发布,PHP,Python,JAVA等代码的发布.回滚,可以通过we ...

  6. Training: MySQL I (MySQL, Exploit, Training)

    题目链接:http://www.wechall.net/challenge/training/mysql/auth_bypass1/index.php?highlight=christmas 的确是非 ...

  7. C#课后小作业

    有关C#基础的练手 跟大家一起分享下 1.让用户输入一个100以内的数 打印1-100之间所有的数,用户输入的数除外 2.让用户输入一个100以内的数 打印1-这个数之间所有的数的和 3.使用一个fo ...

  8. [转]操作系统Unix、Windows、Mac OS、Linux的故事

    [写得很江湖气,可惜找不到原作者了] 文章转自:http://blog.csdn.net/wenmingchan/article/details/49925379 http://www.jb51.ne ...

  9. 转 gerrit

    开发环境 https://blog.csdn.net/u013207966/article/details/79112740 先记录下我的开发环境以及要正确安装gerrit需要用到的工具: Redha ...

  10. Vue学习计划基础笔记(二) - 模板语法,计算属性,侦听器

    模板语法.计算属性和侦听器 目标: 1.熟练使用vue的模板语法 2.理解计算属性与侦听器的用法以及应用场景 1. 模板语法 <div id="app"> <!- ...