重载包括函数重载和运算符重载。区别于虚函数的运行时多态,重载属于编译时多态。
函数重载
函数重载是指功能相似的不同函数可以拥有相同的函数名。虽然函数名相同,但是编译器可以根据函数参数类型、个数的不同识别不同函数。
实现函数重载要满足以下三个条件之一:
- 参数表中对应的参数类型不同;
- 参数表中参数个数不同;
- 参数表中不同类型的参数的次序不同;
在使用函数重载时需要注意以下几点:
(1) 不能利用函数的返回类型进行函数重载,如:
int fun(int);
void fun(int);//非法函数重载
(2) 不能利用函数参数的引用进行函数重载,如:
void fun(int);
void fun(int&);
(3) 函数重载常用于构造函数的重载;
(4) const声明可以用于成员函数的重载,以下重载合法:
void fun(int);
void fun(int)const;
(5) 常函数和普通函数可以以重载的形式共存,具体是常函数还是普通函数取决于调用者的类型。如:
#include <iostream>
class Test{
public:
void print() const;
void print();
}
void Test::print()const
{
cout<<"const print"<<endl;
}
void Test::print()
{
cout<<"print"<<endl;
}
int main()
{
const Test a;
Test b;
a.print();
b.print();
}
运行结果:
const print
关于常函数,需要区分是顶层const还是底层const,这一点将在以后详细说明.
(6) 包含可缺省函数时可能造成二义性;
运算符重载
运算符重载本质上与函数重载是一样的,因为一个运算符完成的运算功能实际上通过运算符函数实现的,进行运算即是调用函数。运算符重载即对已有的运算符赋予多重含义。
使用运算符重载时需要注意以下几点:
(1) 重载的运算符的优先级、运算顺序以及运算分量个数与系统中的原运算符一致,不能自创新的运算符;
(2) 以下运算符不可重载:
- 限定符 . 和::
- 运算符 ?:
- 取长度运算符 sizeof
(3) 赋值运算符=、关系运算符==、!=、指针运算符&和*,下标运算符[ ]等,运算所涉及的数据类型并非只限定于基本数值类型,可自动扩展到用户定义的数据类型,不需要定义重载就可以自动完成重载;
(4) 对于单目运算符++和–,需要区别前缀和后缀。为了区分,在后缀的重载函数的参数列表中增加一个int型的无名参数,如下:
前缀++ : <类型>operator ++() //作为类的成员函数
<类型>operator ++(<类型>) //作为类外函数后缀++ : <类型>operator ++(int) //作为类的成员函数
<类型>operator ++(<类型>,int) //作为类外函数
运算符重载有两种方式:类成员函数方式和类友元函数方式。
(1) 按类成员函数方式重载时有以下特征:
- 类成员函数内可以处理和使用本类的私有成员;
- 总以当前调用者对象(*this)作为该成员函数的隐式第一运算分量,多余的运算对象则以显式的方式列在参数列表中;
- 一般单目运算符采用类成员函数方式。
(2) 按类友元函数方式重载时有以下特征:
- 友元函数内可以处理和使用本类的私有成员;
- 所有运算分量都要以显式的方式列在参数列表中,且这些参数类型中至少有一个是说明该友元的类或是对该类的引用;
- 一般双目运算符采用类友元函数方式。