细说重载
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。
运算符的重载
运算符重载是个什么东西
**运算符重载及将运算符与类结合,产生新的含义。**目的为了实现类的多态性(多态是指一个函数名有多种含义)。
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
那我们如何实现重载呢
方式:类的成员函数 或 友元函数(类外的普通函数)
规则:不能重载的运算符有 . 和 .* 和 ?: 和 :: 和 sizeof
可重载运算符/不可重载运算符
下面是可重载的运算符列表:
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
---|---|
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),–(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
下面是不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号
我们来举个直观的例子
一元运算符重载
声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:
Box operator+(const Box&, const Box&);
类成员函数
**即在类中定义一个成员函数来重载运算符。**下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问,如下所示:
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance()
{
feet = 0;
inches = 0;
}
Distance(int f, int i)
{
feet = f;
inches = i;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
// 重载负运算符( - )
Distance operator-()
{
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
};
int main()
{
Distance D1(11, 10), D2(-5, 11);
-D1; // 取相反数
D1.displayDistance(); // 距离 D1
-D2; // 取相反数
D2.displayDistance(); // 距离 D2
return 0;
}
运行结果如下;
F: -11 I:-10
F: 5 I:-11
友元函数
在类外部定义一个函数来重载运算符,并将这个函数声明为该类的友元函数,以达到可以访问类的私有属性的目的。
#include <iostream>
using namespace std;
class Demo
{
public:
// 友元函数实现运算符重载
friend Demo & operator+ (Demo & demo, int n);
Demo(int a)
{
this->a = a;
}
int getA()
{
return a;
}
private:
int a;
};
// 重载 "+" 运算符
Demo & operator+ (Demo & demo, int n)
{
demo.a += n;
return demo;
}
int main()
{
Demo demo(1);
// 重载 "+" 运算符后,对象可以直接加一个数
demo = demo + 2;
cout << demo.getA() << endl;
return 0;
}
类成员函数和友元函数的区别
- 类成员函数实现默认带有一个 this 指针,而友元函数实现则没有
- 要想实现类似 “cout << obj << endl;” 这样的效果,只能由友元函数重载左移运算符实现(后面介绍)
总结:
- 由于+ -都是出现在=号的右边,如c=a+b,即会返回一个右值,可以返回const型值
- 后几个表达式讨论的就是,数和对象混合运算符的情况,一般出现这种情况,常使用友元函数
二元运算符重载
二元运算符需要两个参数,下面是二元运算符的实例。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。就像加(+)运算符。下面的实例演示了如何重载加运算符( + )。类似地,您也可以尝试重载减运算符( - )和除运算符( / )。
可重载的双目运算符:
,
逗号
<
小于
!=
不等于
<<
左移
%
求模
<<=
左移并赋值
%=
求模并赋值
<=
小于或等于
&
按位与
=
赋值、复制赋值和移动赋值
&&
逻辑与
==
等于
&=
按位与并赋值
>
大于
*
乘
>=
大于或等于
*=
乘并赋值
>>
右移
+
加
>>=
右移并赋值
+=
加并赋值
^
异或
-
减
^=
异或并赋值
-=
减并赋值
|
按位或
->*
指向成员的指针
|=
按位或并赋值
/
除
||
逻辑或
/=
除并赋值
[]
下标运算符
我们下面来举个例子
#include <iostream>