写点什么

C++ 运算符重载(三)之递增运算符重载

作者:CtrlX
  • 2022 年 8 月 11 日
    山东
  • 本文字数:2305 字

    阅读完需:约 8 分钟

C++运算符重载(三)之递增运算符重载

递增运算符重载

作用: 通过重载递增运算符,实现自己的整型数据


重载前置递增运算符


class MyInteger {
friend ostream& operator<<(ostream& out, MyInteger myint);
public: MyInteger() { m_Num = 0; } //前置++ MyInteger& operator++() {//注意& //先++ m_Num++; //再返回 return *this; }

private: int m_Num;};
//左移运算符重载ostream& operator<<(ostream& out, MyInteger myint) {//加上&就是引用传递。 out << myint.m_Num; return out;}

//前置++ 先++ 再返回void test01() { MyInteger myInt; cout << ++myInt << endl;//先++,后输出 cout << myInt << endl;}

int main() {
test01();//输出结果:1 1
system("pause");
return 0;}
复制代码


注意:cout << ++myInt << endl;//先++,后输出


先++,后输出是指先运行成员函数前置递增运算符重载,再运行函数左移运算符重载。所以先++完成后再传入左移运算符重载函数中,要么是引用传递,要么是拷贝传递,上图使用的是拷贝传递,都可。


PS:为什么MyInteger& operator++() {}处要使用 &


//预期目的:两次递增运算都是作用在同一个对象上int a = 0;cout<< ++(++a) <<endl;//2
//如果返回值是引用,那么返回值就是本身,如果返回值是一个值,实际上返回的是一个值的副本,拷贝构造。//若是去除了引用,拷贝构造函数被调用,创建了临时对象,没有在原对象上进行操作,所以输出的不一样。//引用是为了对一个数据进行递增操作MyInteger& operator++() { m_Num++; return *this;}
复制代码


重载后置递增运算符


#include<iostream>using namespace std;
class MyInteger {
friend ostream& operator<<(ostream& out, MyInteger myint);//注意&
public: MyInteger() { m_Num = 0; }
//后置++ ,int代表占位参数,可以用于区分前置和后置递增。 MyInteger operator++(int) { //先返回 MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++; m_Num++; return temp;//拷贝构造 }
private: int m_Num;};
//左移运算符重载ostream& operator<<(ostream& out, MyInteger myint) { out << myint.m_Num; return out;}
//后置++ 先返回 再++void test02() {
MyInteger myInt; cout << myInt++ << endl;//先输出后++ cout << myInt << endl;}
int main() { test02();//输出结果:0 1
system("pause");
return 0;}
复制代码


PS:后置递增返回的原因:


  MyInteger operator++(int) {    //先返回    MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;    m_Num++;    return temp;  }
复制代码


如果返回值是引用,局部对象在当前成员函数执行完后释放,再返回局部对象的引用就是非法操作。如果返回值是一个值,实际上返回的是一个值的副本,因为返回是一个拷贝构造过程,原来的释放了,但是拷贝了一份新的,不受成员函数释放的影响。(详细见前面文章回顾)


这里可以直接 new 一个类,然后就可以返回引用了。


#include<iostream>using namespace std;
class MyInteger {
friend ostream& operator<<(ostream& out, MyInteger& myint);
public: MyInteger() { m_Num = 0; }
//后置++ ,int代表占位参数,可以用于区分前置和后置递增。 //在堆区创建 MyInteger& operator++(int) { temp = new MyInteger(*this); m_Num++; return *temp; }
~MyInteger() {//析构时释放堆区 if (temp != NULL) { delete temp; temp = NULL; } }public: MyInteger* temp ;private: int m_Num;};
//左移运算符重载ostream& operator<<(ostream& out, MyInteger& myint) {//注意此处是取址符 out << myint.m_Num; return out;}
//后置++ 先返回 再++void test02() {
MyInteger myInt; cout << myInt++ << endl;//先输出,后++ cout << myInt << endl;
}
int main() {
test02();//输出结果:0 1
system("pause");
return 0;}
复制代码


注意 1cout << myInt++ << endl;//先输出,后++


虽然是先输出后++,但是运行时同前置递增重载运行顺序,先运行后置递增重载成员函数,再运行左移运算符重载全局函数。


cout << myInt++ << endl;//先输出,后++先调用 左移运算符重载全局函数 输出开辟到堆区的*temp 再对栈区的 myInt 做后置++操作


cout << myInt << endl;之后再执行第二次输出,再次调用 左移运算符重载全局函数 引用传入后置递增后的 myInt,注意易错点:为什么使用引用?


使用引用的原因:解决浅拷贝问题!


如果不加 &符号operator<<(ostream& out, MyInteger myint) 传入的是对 myInt 的拷贝,在这个左移运算符重载全局函数运行完输出之后会对这个拷贝对象进行释放,从而运行了这个拷贝对象中的析构函数,提前释放了堆区数据。当test02()运行完成后会对 myInt 进行释放,从而会再一次运行析构函数去释放堆区的数据从而报错。


注意 2:后置递增因为一直是在对 temp 进行增加,因此无法使用(myint++)++,返回的 temp 的值,再被<<输入时,只能是值的状态。因为执行完++时 temp 已经被释放没有内存空间,也就不能产生同地址的引用。


注意 3:就算是正常的(a++)++这样的语句也会报错。


后置++操作正常是先引用后递增,所以这里用了一个 temp 来记录递增之前的值,而不是直接返回原来的数的引用,但这里确实不可以进行链式操作了,因为返回回来的对象不是原来的对象,返回的对象是 temp。


总结: 前置递增返回引用,后置递增返回

用户头像

CtrlX

关注

Pain is inevitable,suffering is optional 2022.08.01 加入

【个人网站】ctrlx.life 【联系方式】微信:gitctrlx 【软件技能】前端,C++,Python,研究网络工程,数据结构与算法。

评论

发布
暂无评论
C++运算符重载(三)之递增运算符重载_c_CtrlX_InfoQ写作社区