函数重载

重载函数:同一作用域内的几个函数名字相同但形参列表不同:

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& 。

调用重载的函数

函数匹配也叫重载确定,是指一个过程,在这个过程中把函数调用与一组重载函数中的某一个关联起来。

编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较的结果决定到底调用哪个函数。

调用重载函数时有三种可能的结果:

  • 编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码。
  • 找不到任何一个函数与调用的实参匹配,此时编译器发出无匹配的错误信息。
  • 有多于一个函数可以匹配,但是每一个都不是明显的最佳选择。此时将发生错误,称为二义性调用。
posted @ 2019-07-18 14:44  CodeWithMe  阅读(229)  评论(0)    收藏  举报