也是c++对类型处理增强的点,一共比c增强了两个点嘛。还是比较重要的。c++规则是比较多了,若是光看复习文档,非头大不可。所以要学会使用,从实际使用中找到为什么的理由。
运算符重载概念
- 含义:已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时产生不同的行为。
- 目的:使得C++的运算符能够用来操作对象。
不可重载的运算符(七种)
成员访问运算符 | . |
---|---|
成员指针访问运算符 | .* ,->* (点星,与箭头星) |
域运算符 | :: |
长度运算符 | sizeof |
条件运算符 | ?: |
预处理运算符 | # |
除了类相关的基本运算符(成员函数操作符.域操作符::成员指针访问,两个*和->)和预处理运算符#,sizeof及惟一的三目运算符条件?:(这些其实只适用于单个语句,而不适用于类或对象),都是可以重载的。 |
-
实质:编写以运算符为名称的函数,使用运算符表达式被解释为对重载函数的使用。
使用重载的运算符时,会自动调用以运算符为名称的重载函数。虽然本质上是函数调用,但C++允许不写函数调用的形式,而直接写成习惯上的运算符的形式。运算符函数格式:返回值类型 operator运算符(形参表){函数体}
注: operator运算符,可以看作是一个整体或函数名
运算符可以重载为全局函数(通常为类的友元函数,因为全局函数不能访问类的私有成员)。对于二元运算符,需要传递两个参数。但当重载为类的成员函数时,二元运算符可以只传递一个参数。另一个参数隐含。 -
重载运算符的规则:
- 重载后运算符应该符合原来的用法习惯
- 运算符重载不能改变运算符原有的语义,包括运算符优先级和结合性。
- 不能改变运算符操作个数及语法。不能创建新的运算符,即不能超出C++语言允许重载的运算符范围
- (),[],->或者赋值运算符=,只能重载为成员函数,不能重载为全局函数。
- 不能改变基本数据类型对象的含义。可用于用户自定义的类型对象之间的运算,也可用于用户自定义类型的对象与基本数据类型之间的混合运算。
重载赋值运算符
系统提供了默认的重载版本两个运算符:
- 赋值运算符=:系统默认重载为对象成员变量的复制
- 地址运算符&:重载为返回任何类型对象的地址。
注意:
赋值运算必须重载为成员函数不能重载为友元。
为保持与通常意义赋值运算符一致,重载赋值运算符通常所回引用。
浅拷贝:
对象之间通过‘=’,没有重载时就是值的拷贝,称为浅拷贝
如果涉及到指针或引用,则它们之间是相互关联的。
可能造成的问题:
重复释放同一块空间,会产生错误。
某块内存永远不会被释放,会产生内存垃圾。
深拷贝:
重载运算符后,赋值语句的功能是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方,这样的拷贝。
重载流插入运算符和流提取运算符(输入和输出运算符重载)
中已对<<(插入)和>>(提取)1两个运算符进行了重载,用来输出C++基本的数据类型。而要输出自己定义的类的对象信息,就需要对<<进行重载。cout是ostream 类的对象2。cin是istream类的对象。
自定义重载:不能是流类库的成员,而且必须重载为类的友元。
考点
流插入重载格式:
ostream &opreator<<(ostream & output,类名 &对象名)
{...
return output;//output是ostream对象的引用,它是cout的别名
}
注:插入运算符不改变对象的值,所以第二个参数 类名 &对象名或类名 对象名,两种重载方式都是可以的。
实际使用如下所示:
#include <iostream>
using namespace std;
class Complex
{
public:
Complex()
{
real = 0;
imag = 0;
}
Complex(double r, double i)
{
real = r;
imag = i;
}
Complex operator + (Complex &c2); //运算符“+”重载为成员函数
friend ostream &operator << (ostream &, Complex &); //运算符“<<”重载为友元函数
private:
double real;
double imag;
};
Complex Complex::operator + (Complex &c2)//定义运算符“+”重载函数
{
return Complex(real + c2.real, imag + c2.imag);
}
ostream &operator << (ostream &output, Complex &c) //定义运算符“<<”重载函数
{
output << "(" << c.real << "+" << c.imag << "i)" << endl;
return output;
}
int main()
{
Complex c1(2, 4), c2(6, 10), c3;
c3 = c1 + c2;
cout << c3;//重载<<后面的c3为实际传入的类的对象,也就是输出为c3内容
//为什么能输出呢?是因为第一个参数为cout别名,所以表达式为cout<<c3
//cout就是输出类的对象,相当于在输出基本数据类型上又加了一层。
return 0;
}
流提取重载格式:
istream &operator>>(istream &input,类名 &对象名)
{...
return input;//同理,input是cin的别名,引用
}
注:提取需要返回新的对象值,所以第二个参数只能使用引用
重载自增、自减
c++规定 前置运算符为一元运算符重载,后置运算符作为二元运算符重载.用重载的方式实现前置算法与后置算法,如下列代码:
*
* @Description:
* @version:
* @Author: liuJun
* @Date: 2021-06-27 21:55:32
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-28 22:51:32
*/
#include <iostream>
using namespace std;
class Cdemo {
private:
int n;
public:
Cdemo(int i = 0) : n(i) {}
Cdemo &operator++(); //前置形式,返回的是引用对象,代表这个值会改变,前置是先加再返回此对象,所以可以作为左值
Cdemo operator++(int); //后置形式,返回的是临时变量,先返回再加
operator int() { return n; }
friend Cdemo &operator--(Cdemo &);
friend Cdemo operator--(Cdemo &, int);
};
Cdemo &Cdemo::operator++() {
n++;
return *this;
}
Cdemo Cdemo::operator++(int k) {
Cdemo cmp(*this);
n++;
return cmp;
}
Cdemo &operator--(Cdemo &d) {
d.n--;
return d;
}
Cdemo operator--(Cdemo &d, int) {
Cdemo tmp(d);
d.n--;
return tmp;
}
int main(int argc, char const *argv[]) {
Cdemo d(10);
cout << (d++) << ",";//打印d的值 10
cout << d << ",";//打印d++后的值 11
cout << (++d) << ",";//打印++d的值 12
cout << d << ",";//打印++d的值 12
cout << (d--) << ",";// 12
cout << d << ",";//11
cout << (--d) << ",";//10
cout << d << endl;//10
return 0;
}
对比
前置运算符的重载 | 1.变量自增 2.返回引用对象 |
---|---|
后置运算符的重载 | 1.创建临时变量 2.临时变量的增减,3.返回临时对象 |
前置作为左值情形
int a = 0
// (++a) = 5; 可以拆解成:
// a = a + 1;
// a = 5;
(++a) = 5; // 前置++