函数重载:
即C++编译器通过检测同名函数不同的参数列表来进行匹配的行为
几个要点:
- 函数重载的关键是函数的参数列表,也称函数特征标,包括参数的数目,类型,顺序
- 某类型与其引用将视为同一特征标
- const与非const视为不同特征标,const参量可以接受非const变量(反之不可以),假如存在两个参数分别是const和非const的同名函数,传入非const变量时优先匹配非const参数的函数
函数模板:
例交换模板:
template < typename Anytype>
void Swap(Anytype &a,Anytype &b)
{
Anytype temp;
temp=a;
a=b;
b=temp;
}
- 其中关键字template和typename是必须的,但typename可以替换成class
- 当交换两个int变量的值时,编译器会自动按模板创建函数,并将Anytype替换成int.
- 同样的,模板也可以进行重载
- 我们也可以不通过参数实例化函数模板,即在函数调用时在函数名后加< 参数类型1,参数类型2…> (参数)便可指定函数模板生成什么参数类型的函数。
函数模板和函数的次序:
在有多个函数和函数模板名字相同的情况下,编译器如下处理一条函数调用语句
- 先找参数完全匹配的普通函数(非由模板实例化而得的函数)。
- 再找参数完全匹配的模板函数。
- 再找实参数经过自动类型转换后能够匹配的普通函数。
- 上面的都找不到,则报错。
关键字decltype(C++11)
int x;
decltype(x) y;//等价于 int y;
decltype((x)) y;//等价于int & y;
一般用于当模板中某个表达式类型未知时。
后置返回类型(C++11)
对于如下代码:
template<class T1,classT2>
? type gt(class T1,class T2)
{ ...
return x+y;
}
首先我们无法知道T1+T2的类型,这看起来似乎可以使用decltype(x+y)来解决,但实际上此时还没有声明x,y。
所以我们采用后置返回类型来解决:
double h(int x);//等价于auto h(int x) -> double;
所以上例可定义为:
template<class T1,class T2>
auto gt(class T1,class T2) -> decltype(x+y)
{
...
return x+y;
}
运算符重载:
- 运算符重载的实质是函数重载
- 可以重载为普通函数,也可以重载为成员函数
- 把含运算符的表达式转换成对运算符函数的调用。
- 把运算符的操作数转换成运算符函数的参数。
- 运算符被多次重载时,根据实参的类型决定调用哪个运算符函数。
- 重载为成员函数时对象本身就是第一个参数。
运算符重载的形式
返回值类型 operator 运算符(形参表)
{
……
}
赋值运算符 ‘=’ 的重载
- 赋值运算符“ =”只能重载为成员函数
- 重载时返回值尽量为引用以保持原有特性。
友元与重载
什么时候使用友元重载?
- 对某个二目运算符重载成员函数进行补充
class A
{ ...
A operator + (int i);
friend A operator + (int i,A a);
};
//此时a+i与i+a均合法,维持了+号原本的特性。
- 流插入和流提取运算符重载时一般需要写成友元函数
自增,自减运算符的重载
自增运算符++、自减运算符–有前置/后置之分,为了区分所重载的是前
置运算符还是后置运算符, C++规定:
- 前置运算符作为普通一元运算符重载
- 后置运算符作为二元运算符重载,多写一个没用的参数
一般重载前置运算符时需要返回其引用,而重载后置运算符时则返回其对象。这也是为了贴合原来++、- - 运算符的性质
强制类型转换运算符的重载
operator int() {};
- 类型强制转换运算符被重载时不能写返回值类型,实际上其返回值类型就 是该类型强制转换运算符代表的类型
- 一般作为成员函数重载
运算符重载的注意事项
- C++不允许定义新的运算符 ;
- 运算符重载不改变运算符的优先级;
- 以下运算符不能被重载:“ .” 、“ .*” 、“ ::” 、“ ?:” 、 sizeof;
- 重载运算符()、 []、 ->或者赋值运算符=时,运算符重载函数必须声明为
类的成员函数。
类模板
定义
template <class 类型参数1,class 类型参数2,……> //类型参数表
class 类模板名
{
成员函数和成员变量
};
类模板里成员函数的写法:
template <class 类型参数1, class 类型参数2, ……> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
函数体
}
用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实参表);
类模板的“<类型参数表>”中可以出现非类型参数:
template <class T, int size>
class CArray{
T array[size];
public:
void Print( )
{
for( int i = 0;i < size; ++i)
cout << array[i] << endl;
}
};
CArray<double,40> a2;
CArray<int,50> a3; //a2和a3属于不同的类