函数重载
重载函数:同一作用域内的几个函数名字相同但形参列表不同:
void print(const char *p); void print(const int *beg, const int *end); void print(const int ia[], size_t size);
当调用函数时,编译器会根据传递的实参类型推断想要的是哪个函数:
int j[2] = { 0,1 }; print("Hello World");//调用print(const char *p); print(j, end(j) - begin(j));//调用print(const int ia[], size_t size); print(begin(j), end(j));//调用print(const int *beg, const int *end);
main 函数不能重载。
定义重载函数
典型的数据库应用,创建几个不同的函数分别根据名字、电话、账户号码等信息查找记录,函数的名字都是 lookup,但是查找的依据不同:
Record lookup(const Account&);//根据Account查找记录 Record lookup(const Phone&);//根据Phone查找记录 Record lookup(const Name&);//根据Name查找记录 Account acct; Phone phone; Record r1 = lookup(acct);//调用接受Account的版本 Record r2 = lookup(phone);//调用接受Phone的版本
重载函数应该在形参数量或形参类型上有所不同。
不允许两个函数除了返回类型外其他所有的要素都相同。假设有两个函数,形参列表一样但是返回类型不同,则第二个函数的声明是错误的:
Record lookup(const Account&); bool lookup(const Account&);//错误:与上一个函数相比只有返回类型不同
判断两个形参的类型是否相异
有时候两个形参列表看起来不一样,但实际上是相同的:
//每对声明的是同一个函数 Record lookup(const Account &acct); Record lookup(const Account&);//省略了形参的名字 typedef Phone Telbo; Record lookup(const Phone&); Record lookup(const Telno&);//Thlno和Phone的类型相同
- 在第一对声明中,第一个函数给它的形参起了名字,第二个函数没有。形参的名字仅仅起到帮助记忆的作用,有没有它并不影响形参列表的内容。
- 第二对声明看起来类型不同,但事实上 Telno 不是一种新类型,它只是 Phone 的别名而已。
重载和 const 形参
顶层 const 不影响传入函数的对象。一个拥有顶层 const 的形参无法和另一个没有顶层 const 的形参区分开来:
Record lookup(Phone); Record lookup(const Phone);//重复声明了 Record lookup(Phone) Record lookup(Phone*); Record lookup(Phone* const);//重复声明了 Record lookup(Phone*)
每一组的第二个声明和第一个声明是等价的。
如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,此时 const 是底层的:
//对于接受引用或指针的函数,对象是常量还是非常量对应的形参不同 //定义了4个独立的重载函数 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; }
可以对两个非常量的 string 实参调用这个函数,但返回的结果仍然是 const string 的引用。
一种新的 shorterString 函数,当实参不是常量时,得到的结果是一个普通的引用,使用 const_cast 可以做到这一点:
string& shorterString(string& s1, string& s2) { auto &r = shorterString(const_cast<const string&>(s1), const_cast<const string&>(s2)); return const_cast<string&>(r); }
将实参强制转换成对 const 的引用,调用了 shorterString 函数的 const 版本返回对 const string 的引用,引用事实上绑定在了某个初始的非常实参上,再将其转换回一个普通的 string& 。
调用重载的函数
函数匹配也叫重载确定,是指一个过程,在这个过程中把函数调用与一组重载函数中的某一个关联起来。
编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较的结果决定到底调用哪个函数。
调用重载函数时有三种可能的结果:
- 编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码。
- 找不到任何一个函数与调用的实参匹配,此时编译器发出无匹配的错误信息。
- 有多于一个函数可以匹配,但是每一个都不是明显的最佳选择。此时将发生错误,称为二义性调用。

浙公网安备 33010602011771号