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的转化会被自动提升至int Button 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
}原文地址:http://blog.csdn.net/yuanliang01xiaolang/article/details/41282525