首页 > 代码库 > C++总结之函数重载
C++总结之函数重载
1)函数名称相同
2)函数声明在同一个作用域内(一个类构成一个作用域,因此子类不能重载继承自父类的函数,多继承时,继承自不同父类的函数也不能构成重载)
example:
class Person { public: void love(){} }; class Man:public Person { private: void love(int i){} }; class Car { public: void on() { } }; class Computer { public: void on(int arg) { } }; class ModernCar:public Car,public Computer { }; void love() { Man m; m.love(); ///错误,函数名称的查找期间并不区分访问限制 ///继承自父类的同名函数不能构成重载,已被隐藏尽管子类的love(int)是private的,而父类的love是public的 ModernCar mc; mc.on(); ///错误,来自不同空间的函数不能重载,导致歧义 }
3)using声明的引入对函数的重载有影响,其中using namespace相当于把某个命名空间内的名称复制到当前作用域,而using namespace::name 则相当于告知编译器在namespace中查找name。具体影响看例子:
example:
namespace XXX { void fx() { cout<<"xxx"<<endl; } } void fx(int a) { cout<<"::"<<endl; } void fca() { ///ok using namespace XXX; fx(0); fx(); } void fcb() { using XXX::fx; fx(); ///ok; fx(0); 错误, }
4)函数形参的个数或者类型不同,普通类型的形参不区分const,指针或者引用类型的形参其指涉物的const型别不同也可以构成重载。对于成员函数而言是否为const函数,是针对右值还是左值的函数也可以构成重载。函数的返回值类型不能构成重载
///这两个函数不构成重载,有歧义 int love(int i) { } void love(const int i) { } ///这四个函数构成重载 void love(int *p) { } void love(const int *p) { } void love(int &arg) { } void love(const int &arg) { } class Boy { public: ///这两个函数构成重载 void love()const { } void love() { } }; class Girl { public: ///这两个函数构成重载 void love()& { } void love()&& { } };
5)函数调用发生时,先从最里层的作用域查找函数名,如果未找到,再到外层查找,直到全局空间,如果任未找到相同的函数名,则查找失败。一旦在某一层找到了相同的函数名,马上停止向外层空间的查找,该层空间所找到的所有相同函数名构成候选函数(对于类作用域来说,父类是子类的外层作用域;对于多继承来说,一个子类会出现多个外层空间,此时,每个外层空间都平等对待,即不存在找到名字后马上停止的情况,而是要查找完它所有的父类,该过程完成后,如果出现不同父类拥有同名函数,则调用出错)第一个例子已经可以说明这个问题了
6)函数名查找成功,则判断可以调用的函数组,实以调用的函数其形参个数和实参必须相同,实参必须可以转化到形参,如果没有可以调用的函数,则调用出错。
7)可调用函数组确定下来以后,根据实参到形参所需做的转化类型判断最佳调用。如果没有最佳调用,则调用出错。
8)形参到实参的转化排序:
①精确匹配,即形参和实参个数类型完全一致
实参到形参的转化是数组名或函数名到其对应指针的转化
针对对象本身的const转化(对于引用来说不存在常引用,因此不存在这种类型的转化,对于指针来说是指指针本身常量属性的转化)
②实参到形参需要常量转化,只有唯一一种情况:给指涉到常量对象类型的指针或引用形参传递一个普通的实参对象
③实参到形参的转化通过数值提升
④实参到形参的转化需要算术或指针转化
⑤类类型的转化
9)除此之外,小于int的整数类型会被自动提升至int类型。在一次实参到形参的转化中,类类型的转化只能发生一次。
void love(short s) { cout<<"I love short"<<endl; } void love(int i) { cout<<"I love int"<<endl; } class Button { public: Button()=default; Button(const string &s):name(s){} Button(string &&s):name(move(s)){} private: string name; }; void love() { love('c'); ///output:I love int <pre name="code" class="cpp"> ///小于int的转化会被自动提升至intButton bx("Ok"); ///由"OK"转化至string属于一次类类型转化,然后紧接着可以直接调用 ///Button(string &&)构造函数 Button by = "Reset"; ///错误,由"Reset"到string属于一次类类型转化 ///由于采用复制构造,因此需要将string再转化为Button才可以调用其复制 ///构造函数,故而需要两次类类型转化,而这是不被允许的 }
10)实参到形参的转化过程中如果有类类型转化参与,只有当两个函数提供相同的类类型转化时才考虑数值转化,否则调用出现歧义,主要是在写类的类型转化函数式需要注意,一般算术类型和类类型的转化只需提供一个转化函数,其余的转化可以自动进行。
class Demon { public: Demon()=default; Demon(int){} Demon(double){} operator int()const { return 0; } operator double()const { return 0.0; } }; void love(long double d) { } void love() { Demon d; love(d); ///错误,可通过不同的类类型转化得来, ///其后的算数转化优先级不再考虑,产生歧义 }
11)类的运算符重载需要考虑的重载函数既有类的成员函数,也有非成员函数
class Woman { public: bool operator==(const Woman &w) { return true; } }; class Girl { public: bool operator==(const Girl &g)const { return true; } }; bool operator==(const Girl &g,const Woman &w) { cout<<"Woman isn't equal to Girl"<<endl; return false; } bool operator==(const Woman &w,const Girl &g) { cout<<"Girl isn't equal to Woman"<<endl; return false; } void gw_equal() { Girl ga,gb; Woman wa,wb; cout<<(ga == gb)<<endl; ///output:1 cout<<(wa == wb)<<endl; ///output:1 cout<<(ga == wa)<<endl; ///output: ///Woman isn't equal to Girl ///0 cout<<(wa == ga)<<endl; ///output: ///Girl isn't equal to Woman ///0 }
C++总结之函数重载