初学c++重载函数

什么是重载函数呢,在c++primer中文版(第四版)中是这样解释的:
出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则称为重载函数。

void func(){}
void func(int a){}
void func(int a, int b){}
void func(double a, double b){}

上面这四个函数就是重载函数,但这样说显得太笼统了,因为重载函数中有很多需要理解的地方,下面我就自己所学到的知识来讲一讲这些地方。

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

首先举一个例子

void func(int a){}
int func(int a){}

这两个函数算不算重载函数呢?我们稍后再说,先来看看编译器是怎么分辨重载函数的。

从编译器的角度来说,在汇编之后生成的.obj文件中,含有一个.symtab:符号表,存放程序中定义和引用的函数和全局变量信息,不包含局部变量条目。

这个符号表也是gcc(.c)文件和gcc(.cpp)文件在编译链接过程中的一个区别:
.c文件在生成符号表时,函数的符号是基于函数名来生成的。
.cpp文件在生成符号表时,函数的符号是基于函数名+形参列表来生成的。

那么答案就推出来了,因为该符号表没有将返回类型也列成符号告诉编译器我们两个是不同的,因此这两个函数无法构成重载。


2.使用typedef重命名的类型也无法进行重载

typedef int DATA;
void func(DATA a){}
void func(int a){}

这两个函数也无法进行重载,因为DATA并不是新类型,而是int类型的同义词,typedef只是给已存在的类型一个别名,并不是创建新类型。
所以,如果两个形参的差别只是一个使用 typedef 定义的类型名,而另一个使用 typedef 对应的原类型名,则这两个形参并无不同。

这里写图片描述


3.使用const修饰形参的类型是否也重载

“可基于函数的引用形参是指向 const 对象还是指向非 const 对象,实现函数重载”

void func1(int a){}
void func1(const int a){}

void func2(int *a){}
void func2(const int *a){}

void func3(int *a){}
void func3(int *const a){}

void func4(int *a){}
void func4(int const *a){}

首先我们需要了解const修饰符的意义:保护被修饰的内容无法被修改。

int const a;
const int a;

这两个定义中,const的意义相同,都修饰 a,表示a为常量不可修改。

int const *b;
const int *b;

这两个定义中,const意义也相同,都修饰*b,表示*b不可修改,但是b指向的地址可以被改变。

因此可以看到以下两个函数的意义相同:

void func2(const int *a){}
void func4(int const *a){}

而在学习中我了解到,区分形参含有const是否重载的一种方法。
“对于指针及引用来说,看能否通过修改形参,来影响实参的值”
(只有两个函数中的一个可以影响实参的值,一个不可以影响的时候,才会产生重载)

void func1(int a){}
void func1(const int a){}

对于func1()来说:
第一个函数可以修改形参,但不会影响实参的值。因为在函数栈帧的调用过程中,传进函数的并不是实参,而是实参的拷贝。此时修改形参并不能影响到实参的值。
第二个函数不可修改形参,同样也不可影响实参的值。
因此这两个函数无法重载。

void func2(int *a){}
void func2(const int *a){}

对于func2()来说:
第一个函数可以通过修改形参的值,并影响到实参的值。
第二个函数不可以修改形参的值。
因此这两个函数可以重载。

void func3(int *a){}
void func3(int *const a){}

对于func3()来说:
第一个函数可以通过修改形参,并影响到实参的值。
第二个函数中,const修饰的是a,无法修改的是a所指向的内存空间,但是a指向内存空间的值并未被const修饰,可以修改,并影响到实参的值。
因此这两个函数无法重载。


编译器关于重载函数的匹配

c++primer中文版(第四版)中是这样描述重载函数匹配的:
1. 编译器找到与实参最佳匹配的函数,并生成调用该函数的代码。
2. 找不到形参与函数调用的实参匹配的函数,在这种情况下,编译将给出编译错误信息。
3. 存在多个与实参匹配的函数,但没有一个是明显的最佳选择。这种情况也是,该调用具有二义性。

我们下面用一个重载函数来详细描述重载函数的匹配

void func();
void func(int);
void func(int, int);
void func(double, double = 3.14);

当我们传入以下实参时,编译器会怎么样调用重载函数呢?

func(10.3);

第一步:选出候选函数。候选函数是与被调函数同名的函数,并在调用点上声明可见。此例中,与func同名的有四个函数。

第二步:从候选函数中选择一个或多个函数,他们可以用该调用中指定的实参来调用。这些函数叫做可行函数。可行函数必须满足两个条件:
1、函数的形参个数与该调用的实参个数相同;
2、每个实参类型必须和形参类型相匹配,或者可隐式转换为对应的形参类型。
(批注:如果调用函数具有默认实参,则调用该函数时传入实参个数可能比形参个数少。默认实参也是实参,在处理时和其他实参一样。)

传入一个double类型数据时,该数据可能会隐式转换为int类型,因此下面这个函数为可行函数。

void func(int);

传入一个double类型数据时,下面这个函数也为可行函数,因为该函数为第二个参数提供了实参,且第一个函数同为double类型,与实参类型精确匹配。

void func(double , double = 3.14);

第三步:寻找最佳匹配函数

对于func(int ); 来说,需要进行隐式转换,而func(double,double = 3.14); 来说,该实参精确匹配。所以第二个函数是最佳匹配函数,编译器会选择调用第二个函数。


含有多个形参的重载确定

void func(int, int );
void func(double, double );
func(12,3.5);

在调用func(12,3.5);时,编译器会选出上面两个可行函数,接着进行最佳函数匹配。如果有且仅有一个函数满足下列条件,则匹配成功:
1. 其每个实参的匹配都不劣于其他可行函数需要的匹配。
2. 至少有一个实参的匹配优于其他可行函数提供的匹配。

在检查所有实参之后,仍找不到最佳匹配,则调用错误,编译器会提示该调用具有二义性。

这里写图片描述


到这里重载函数学习完毕,应该还有很多没有涉及到的地方,在以后的学习中慢慢添加。关于const与成员函数的重载在以后深入学习后再添加。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值