C++ primer第六章6.4函数的学习 之函数的重载

6.4 函数的重载

  • 函数的名字相同但是形参的列表不同,将其称之为重载函数
void print(const char *cp);
void print(const int *beg,const int * end);
void print(const int ia[],size_t size);
  • 形如上面所展现的这样,当调用这些函数的时候,编译器会根据传递的实参类型推断出想要的是哪个函数。
  • 重载函数在一定程度上减轻了程序员对于起名字和记名字的负担。
  • mian函数不可以重载

定义承载函数

  • 比如数据库的应用场景中,定义一个查询的函数,对于手机号、名字、账户号码分别进行查询。他们虽然查询的东西不一样,但是函数的名字是一样的,编译器会根据传入的实参的类型决定调用哪一个函数。
  • 对于重载函数而言,应该在形参的数量、类型有所不同。
  • 不允许两个函数除了返回的类型不同,形参列表都相同。那么第二个声明是错误的。

判断两个形参的类型是否不同

  • 有时候两个形参列表看起来不一样,但是实际上是相同的
//每队声明的是同一个函数
record lookup(const Account &acct);
record lookup(const Account &);    //省略了形参的名字
typedef Phone Telno;
record lookup(const Phone&);
record lookup(const Telno&);    //Phone Telno类型一样

重载和const形参

  • 顶层const不影响传入函数的对象。一个拥有顶层const的形参无法和一个没有顶层const的形参区分开来。
record lookup(Phone);
record lookup(const Phone);//重复声明
record lookup(Phone*);
record lookup(Phone* const);//重复声明
  • 如果形参是某种类型的指针或者引用,则通过区分其指向的是常量对象还是非常量对象实现函数的重载,这个时候const是底层
//对于接受引用或者指针的函数而言,对象是常量还是非常量对应的形参不同
//定义了四个独立的重载函数
record lookup(Account&);//函数作用于Account的引用
record lookup(const Account&);//新函数,作用于常量的引用
record lookup(Account*);//新函数,函数作用于Account的指针
record lookup(const Account*);//新函数,作用于指向常量的指针
  • 编译器可以通过实参是否是常量来推断调用哪个函数。因为const不可以转化成其他的类型,所以只可以将const对象(指向const的指针)传递给const的形参。
  • 非常量可以转化成const,所以上面的四个函数都能作用于非常量对象或者指向非常量对象的指针。当传递一个非常量对象或者非常量对象的指针的时候,编译器会优先选用非常量版本的函数。

建议:何时不应该使用重载函数

  • 最好用于指向那些确实非常相似的操作

const_cast和重载

  • 先前
//跳出两个string对象中较短的那个,并且返回其引用
const string &shorterString(const string &s1,const string &s2){
    return s1.size() < s2.size() ? s1 : s2;
}
  • 引入一个新的函数,相较于先前的函数,当他的实参不是常量的时候,得到的结果是一个普通的引用,使用const_cast就可以实现这一点。
  • 改进
string &shorterString(string &s1,string &s2){
    auto &r = shorterString(const_cast<const string&>(s1),const_cast<string&>(s2));
    return const_cast<string&>(r);
}

int main(){
    string s1 = "Hello";
    string s2 = "Hello World";
    cout << shorterString(s1,s2) << endl;

}
  • 改进是在先前的基础上进行封装了一层,里面还是调用了先前的版本。
  • 改进的版本,首先是将他的实参强制类型转化成对于const的引用,然后调用了先前的版本,由先前的版本返回对于const string的引用,这个引用事实上绑定在某个函数初始的非常量的实参上。因此,可以再次将其转化成一个普通的string&,这个过程显然是安全的。

调用重载的函数

  • 在对于重载的函数进行使用的过程需要一个函数匹配的的过程,这个过程是把函数的调用和一组重载函数中的某一个关联起来,函数的重载也叫重载确定。
  • 编译器会根据调用的实参与重载集合中的每一个函数的形参进行匹配,然后根据比较的结果决定到底使用哪个函数
  • 但是有些情形,对于重载函数的比较会很难,比如,当两个重载函数参数的数量相同和参数的类型可以相互转化的时候。

匹配的结果

  • 1,编译器找到一个与实参最佳匹配的函数,并生成调用这个函数的代码。
  • 2,找不到一个函数和调用的实参相互匹配,此时编译器会提示无匹配的错误
  • 3,对于一个函数可以匹配,但是每一个都不是最佳的选择,这个时候也是错误,称为二义性调用。

6.4.1 重载和作用域

  • 重载对于函数的作用域并没有什么特别的改变,如果在内层作用域中声明名字,它将隐藏外层作用域中声明的同名的实体。在不同的作用域中无法重载函数的名字。
  • 原则:将函数的声明置于局部的作用域之内不是一个明智的决定,这里仅仅为了举例子
void print(const string &);
void print(double );//重载print函数
void fooBar(int ival){
//    bool read = false; //新的作用域:隐藏外层的read,如果把这一行注释掉,那么string s = read();就不会出错
    string s = read(); //如果上面一行存在,会出错,因为read是一个布尔值,而不是函数
    cout << s << endl;
}
int main(){
    fooBar(1);
}

猜你喜欢

转载自blog.csdn.net/CHYabc123456hh/article/details/109015139