我们之前在 C 语言中学习了前置 ++ 和后置 ++。应该知道 i++ 是将 i 的值作为返回值,i + 1;++i 是先 i+1,再返回 i 的值。那么它们真的有区别吗?我们来编程看看,在 VS 中进行反汇编,看看汇编代码是怎样处理的

#include<iostream>usingnamespacestd;intmain(){inti=0;i++;++i;return0;}

我们看到在程序中仅仅是实现 i++ 和 ++i 的操作,看看反汇编,汇编的代码是怎样处理的

我们看到它们两个的处理在汇编层面是一样的,并没有什么区别。那么这是怎么回事呢?现代的编译器已经在自动优化了,因为它看到我们只是进行 ++ 操作,并没有用到它的返回值。所以就自作主张的给优化了,其实这样优化后,二进制程序的效率更加高效了。但是优化后的二进制程序丢失了 C/C++ 的原生语义,因此我们不可能从编译后的二进制程序去还原 C/C++ 程序。

那么 ++ 操作符可以重载吗?如果可以,那它如何区分前置 ++ 和后置 ++ 呢?在 C++ 中,++ 操作符是可以被重载的,全局函数和成员函数均可进行重载,重载前置 ++ 操作符不需要额外的参数,但在重载后置 ++ 操作符时需要一个 int 类型的占位参数。

我们下来用程序来实现下 ++ 操作符的重载

#include<iostream>#include<string>usingnamespacestd;classTest{intmValue;public:Test(inti){mValue=i;}intvalue(){returnmValue;}Test&operator++(){++mValue;return*this;}Testoperator++(int){Testret(mValue);mValue++;returnret;}};intmain(){Testt1(0);Testt2(0);Testtt1=t1++;cout<<"tt1.value="<<tt1.value()<<endl;//0cout<<"t1.value="<<t1.value()<<endl;//1Testtt2=++t2;cout<<"tt2.value="<<tt2.value()<<endl;//1cout<<"t2.value="<<t2.value()<<endl;//1return0;}

我们看到后置 ++ 操作符有一个 int 类型的占位参数。在进行 tt1 = t1++ 后,tt1 的值应该为 0,而 t1 的值应该为 1 了。而 tt2 = ++t2,两个应该都为 1 了。我们看看编译结果

我们看到结果和我们所分析的是一致的,也就是说我们的 ++ 操作符已经成功实现了。那么现在的 i++ 和 ++i 还有区别吗?肯定是有的!对于基础类型的变量:前置 ++ 的效率与后置 ++ 的效率基本相同,根据项目组的编码规范进行选择;而对于类类型的对象:前置 ++ 的效率高于后置 ++,尽量使用前置 ++ 操作符来提供程序的效率。因为后置的操作符需要在栈上生成对象,所以效率比较低。那么我们下来来进一步完善复数类


Complex.h 源码

#ifndef_COMPLEX_H_#define_COMPLEX_H_classComplex{doublea;doubleb;public:Complex(doublea=0,doubleb=0);doublegetA();doublegetB();doublemodulus(constComplex&c);Complexoperator+(constComplex&c);Complexoperator-(constComplex&c);Complexoperator*(constComplex&c);Complexoperator/(constComplex&c);booloperator==(constComplex&c);booloperator!=(constComplex&c);Complex&operator=(constComplex&c);Complex&operator++();Complexoperator++(int);};#endif


Complex.cpp 源码

#include"Complex.h"#include<math.h>Complex::Complex(doublea,doubleb){this->a=a;this->b=b;}doubleComplex::getA(){returna;}doubleComplex::getB(){returnb;}doubleComplex::modulus(constComplex&c){returnsqrt(a*a+b*b);}ComplexComplex::operator+(constComplex&c){doublena=a+c.a;doublenb=b+c.b;Complexret(na,nb);returnret;}ComplexComplex::operator-(constComplex&c){doublena=a-c.a;doublenb=b-c.b;Complexret(na,nb);returnret;}ComplexComplex::operator*(constComplex&c){doublena=a*c.a-b*c.b;doublenb=a*c.b+b*c.a;Complexret(na,nb);returnret;}ComplexComplex::operator/(constComplex&c){doublecm=c.a*c.a+c.b*c.b;doublena=(a*c.a+b*c.b)/cm;doublenb=(b*c.a-a*c.b)/cm;Complexret(na,nb);returnret;}boolComplex::operator==(constComplex&c){return(a==c.a)&&(b==c.b);}boolComplex::operator!=(constComplex&c){return!(*this==c);}Complex&Complex::operator=(constComplex&c){if(this!=&c){a=c.a;b=c.b;}return*this;}Complex&Complex::operator++(){a+=1;b+=1;return*this;}ComplexComplex::operator++(int){Complexret(a,b);a+=1;b+=1;returnret;}


Test.cpp 源码

#include<iostream>#include<string>#include"Complex.h"usingnamespacestd;intmain(){Complexc1(0,0);Complexc2(0,0);Complexc3=c1++;cout<<"c3.a="<<c3.getA()<<",c3.b="<<c3.getB()<<endl;cout<<"c1.a="<<c1.getA()<<",c1.b="<<c1.getB()<<endl;Complexc4=++c2;cout<<"c4.a="<<c4.getA()<<",c4.b="<<c4.getB()<<endl;cout<<"c2.a="<<c2.getA()<<",c2.b="<<c2.getB()<<endl;return0;}

应该是 c3 的 a 和 b 都是 0,c1 的 a 和 b 都是 1;c4 的 a 和 b 都是 0,c2 的 a 和 b 都是 1。我们来编译下看看结果

我们看到编译的结果和我们所分析的是一致的。通过对 ++ 操作符的学习,总结如下:1、编译器优化使得最终的可执行程序更加高效;2、前置 ++ 操作符和后置 ++ 操作符都可以被重载;3、++ 操作符的重载必须要符合其原生语义;4、对于与基础类型,前置 ++ 与后置 ++ 的效率几乎相同,但对于类类型,前置 ++ 的效率高于后置 ++。


欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。