C++函数重载

函数重载

定义重载函数

  函数重载也成为函数多态,是C++在C语言的基础上新增的功能。默认参数使得能够使用不同数目的参数调用同一个函数,而函数多态使得能够使用多个同名的函数

void print(const chat *str, int width); // #1
void print(double d, int width); 		// #2
void print(long l, int width); 			// #3
void print(int i, int width); 			// #4
void print(const chat *str); 			// #5
    
print("abav",15); 	// use #1
print("abaf");		// use #5
prin(1999.0,10);	// use #2
print(1999, 12)		// use #4
print(1999L, 15);	// use #3

// 但是,如果有以下情况
unsigned int year = 3210;
print(year, 6);	// ambiguous call	调用失败	不与任何原型匹配

  如果没有匹配的原型,编译器将尝试使用标准类型转换强制进行匹配。就是说如果#2原型是唯一的原型,则函数调用print(year, 6)将会把year转换成double类型。但在上面代码中,有三个数字作为第一个参数的原型,因此有三种转换方式,这种情况下编译器拒绝调用,并视为错误。

double cube(double x);
double cube(double &x);

  上面所示的代码示例是错误的,此处并没有使用函数重载。虽然他们的特征标量看起来不一样,但实际上都是类似的,只不过一个引用类型,一个非引用类型。从编译器角度来考虑此问题,假设有以下代码

cout << cube(x);

显然,参数x与double x原型和double &x原型都匹配,因此编译器无法分辨使用哪个原型。

所以,为避免混乱,编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。

此外,匹配函数时,要区分const和非const变量。非const值赋给const值这种操作时合法的,反之非法。

long gronk(int n, float m);
double gronk(int n,float m);

不允许以上面的方式重载gronk()。返回类型可以不同,但特征标必须不同。

重载和const形参

  如果对const的使用不太熟悉,请先看这一篇文章 C++之const限定符 !!!

​ 顶层const不影响传入函数的对象。一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开

// 重复声明了Record lookup(Phone)
Record lookup(Phone);
Record lookup(const Phone); 	// 拥有顶层const的形参

// 重复声明了Record lookup(Phone *)
Record lookup(Phone *);
Record lookup(Phone * const); // 拥有顶层const的形参

这两组函数声明中,每一组的第二个声明和第一个声明是等价的。

  如果形参是某种类型的指针和引用,则通过区分其指向是常量对象还是非常量对象可以实现函数重载,此时const是底层的

// 对于接受引用或指针的函数来说,对象是常量还是非常量对应形参不同
Record lookup(Account&);	// 用于Account的引用
Record lookup(const Account&);	// 新函数 作用于常量引用

Record lookup(Account*);	// 新函数 作用于只想Account的指针
Record lookup(const Account*);	// 新函数 作用于指向常量的指针

  上述例子中,编译器可以通过实参是否是常量来判断应该调用哪个函数。因为const指针不能转换成其他类型,所以只能把const对象传递给const形参。相反,因为非常量可以转换为const,所以上面的4个函数都能作用域非常量对象或者指向非常量对象的指针。

  当传递一个非常量对象或者指向非常量对象的指针时,会优先选用非常量版本的函数!

const_cast 和重载

  现有如下函数:

// 比较两个string对象的长度,返回较短的那个引用
const string &shorterString(const string &s1, const string &s2){
	return s1.size() <= s2.size() ? s1 : s2;
}

  函数的参数和返回类型都是const string的引用。可以对两个非常量string实参调用同这个函数,但返回结果仍然是const string的引用(存在隐式转换)

  现在需要一种新的shorterString函数,当它的实参不是常量时,得到的结果是一个普通的引用,使用const_cast可以做到这一点:

// 这个函数重载是被允许的!
string &shorterString(string &s1, string &s2){
	auto &r = shorterSting(const_cast<const string&>(s1), const_cast<const string&>(s2));
	return const_cast<string>(r);
}

  执行流程:首先将它的实参强制转换为成对const的引用,然后调用shorterString函数的版本。const版本返回对const string的引用,可将其转换成一个普通的string&,这显然是安全的!

调用重载的函数

  函数匹配是指一个过程,在这个过程中把函数调用与一组重载函数中的某一个关联起来,函数匹配也叫做重载确定。编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较的结果决定到底调用哪个函数。

  但是在一些情况下选择函数就比较困难,比如当两个重载函数参数数量相同且参数类型可以相互转换时,转换需要进行决策

重载与作用域

一般来说将函数声明放置于剧本作用域内并不是一个明智的选择

在C++语言中,名字查找(函数查找)发生在类型检查(参数类型检查)之前!

  重载对作用域的一般性质并没有什么改变:如果我们在内层作用域中声明名字,将会隐藏外层作用域中声明的同名实体在不同的作用域中无法重载函数名

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
	print(ival);		// 正确:当前print(int)可见
	print(3.14);		// 正确:调用print(int); print(double)被隐藏了
}

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

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值