1.写++之前先了解++a和a++的区别
int a=10;
cout<<"cout<<a++: "<<a++<<endl;//10
cout<<"cout<<a: "<<a<<endl;//11
int b=10;
cout<<"cout<<++b: "<<++b<<endl;//11
cout<<"cout<<b: "<<b<<endl;//11
a++是先赋值,再加1,再把+1后的值赋给a
++a是先加一,再把+1后的值赋给a, 但是最终的a结果都一样,都是加一后的新数,但是再和<<配合使用的时候就会出现上面的错误。
前置++和后置++,有4点不同:返回类型不同、形参不同、代码不同 前置和后置均值的是++号的前置和后置
1.返回类型不同
前置++的返回类型是左值引用,后置++的返回类型const右值。而左值和右值,决定了前置++和后置++的用法。
++a的返回类型为什么是引用呢?
这样做的原因应该就是:与内置类型的行为保持一致。前置++返回的总是被自增的对象本身。因此,++(++a)的效果就是a被自增两次。
但(a++)++就会报错(会显示表达式必须是可修改的左值),原因就是a++的返回类型不是引用,第一次++后返回的对象是临时对象,不是本体,而那个临时对象很快会被释放内存,我们根本就找不到第二次++的对象。
2.形参的区别
前置++没有形参,而后置++有一个int形参,但是该形参也没有被用到。很奇怪,难道有什么特殊的用意?
其实也没有特殊的用意,占位参数,只是为了绕过语法的限制。
前置++与后置++的操作符重载函数,函数原型必须不同。否则就违反了“重载函数必须拥有不同的函数原型”的语法规定。再说了,俩函数一样,我编译器怎么知道调用哪个?
虽然前置++与后置++的返回类型不同,但是返回类型不属于函数原型。为了绕过语法限制,只好给后置++增加了一个int形参。占位参数
原因就是这么简单,真的没其他特殊用意。
3.代码实现的区别
前置++的实现比较简单,自增之后,将this返回即可。需要注意的是,**一定要返回this**。因为是引用返回,所以返回本身就行。
后置++的实现稍微麻烦一些。因为要返回自增之前的对象,所以先将对象拷贝一份,再进行自增,最后返回那个拷贝。因此无法使用引用返回,因为我们不能返回一个局部变量,为什么不行这里不再赘述。
C++Primer中(P132)有这样简介的描述:
前置版本将对象本身作为左值返回,后置版本则将原始对象的副本作为右值返回,两种运算符必须作用于左值运算对象。后置版本需要拷贝副本,所以会影响程序的性能。
++类型的重载运算符放在类内,用类的成员函数实现最合适,全局函数有诸多不便,下面会一一介绍。
上面也已经介绍了,++类型的重载分为前置重载和后置重载。(必须依托类)
#include <iostream>
using namespace std;
class person {
public:
//<<的重载函数,cout相当于调用了<<这个函数,
//设置为友元函数,不然无法访问person的私有数据成员。顺便复习一下友元知识
friend ostream& operator<<(ostream& cout, person p);
person(int a, int b) {
m_A = a;
m_B = b;
}
//前置++,(++a)内置引用属性,所以我们重载后的也要赋予其引用返回的属性
person &operator++() {
m_A++;//至于这里是++m_A还是m_A都可以,原理性的东西一想就行。
m_B++;
return *this;//返回调用当前函数的对象实体
}
//后置++(a++)不用引用,不要破坏原有的机理,我们的目的就是做一个高仿,不是重新定义机理,容易乱
person operator++(int) {
person temp = *this;//因为要返回自增前的对象,所以先拷贝一份,待会儿再把那个备份返回去。
m_A++;//++m_A也行,没必要在这纠结这么多。
m_B++;
return temp;
}
private:
int m_A;
int m_B;
};
//<<运算符的重载,
ostream& operator<<(ostream &cout,person p) {
cout << p.m_A << " "<< p.m_B << endl;
return cout;
}
int main()
{ person p1(1, 1);
cout << "cout<<p++ : "<<p1++; //如果上面的<<重载函数形参列表的person写成引用的话就不能写成 cout<<p++;
//因为我后者++返回的是一个局部变量temp,而temp是一个临时对象,而我不能引用一个临时对象,,临时对象只能传值传进去
cout << "p1自增后的值:"<<p1;
person p2(1, 1);
cout <<"cout<<++p2:"<<++p2;//前置引用有天生的引用属性,先++,再返回p2本体
cout <<"p2自增后的值:"<< p2;//而不是像后置那样返回一个原值的拷贝。
}
结果分析:
我们发现,若单独输出自增后的值相同,但是如果将自增和cout输出语句一块使用就会出现差异,并且此差异和重载前一模一样,所以此重载函数符合我们的要求。