浅谈C++中如何重载前置++/--与后置++/--
前置++/–与后置++/–
C++中的++和–操作符存在前置式与后置式,最基本的,作为一名程序员,你应当了解它们实现的不同:
i++;
++i;
以上两行代码如果单独使用,在功能上是一致的,它们都实现了让变量i加1的操作,但是实现的机制有所不同:
- i++是先用后加,即你在t时刻得到的变量i的值实际上还是原来的值,但它实际的值已经被加1;
++i是先加后用,即你用的值和变量i当前时刻的值是一样的;
int a = 1;
int b = 1;
cout << "a: " << a << " 前++: " << ++a << " a:" << a << std::endl;
cout << "b: " << b << " 后++: " << b++ << " b:" << b << std::endl;
运行结果:
a: 1 前++: 2 a:2
b: 1 后++: 1 b:2
发现没有?后置式其实是将变量的值找了个临时变量先存了起来,然后再将该变量加1,而前置式则直接将变量加1。
从这个机制上,可以下个结论,后置式在性能上要逊与前置式。这其实也是在建议你,在写for循环时尽量使用前置式++i,而不是后置式i++。
前置++/–与后置++/— 的重载
C++允许这两个操作符拥有重载能力。但是这时候你可能发现在语法上似乎出现了问题:重载函数是以其参数类型或个数来区分彼此的,然而这是个单目运算符,无论是前置式还是后置式,都没有参数。于是,为了填平这个语言上的漏洞,只好让后置式有一个int自变量,在其被调用的时候,编译器默默为该int指定一个0值。
假设我们有一个复数类complex,现在为其重载++运算符:
class complex
{
public:
complex& operator++()
{
a = a+1;
b = b+1;
return *this;
};
const complex operator++(int)
{
complex temp = *this;
++temp;
return temp;
};
int a = 0;
int b = 0;
};
其实,前置++与后置++的功能”先加后用“与”先用后加“已经为这两种操作符的实现指明了路线:既然是先加后用,那加完之后的和最后使用的应当是同一样东西,所以应当返回引用。同理,”先用后加“说明应当先把原来的值保存起来,再将其加1,但是最后还是应当返回其原来的值,因为是”先用后加“嘛。另外,你还应当注意,这里保存完原来的值之后,直接调用了前置++去实现加1,这种操作很好的实现了复用,应当被提倡。
但是,你可能会奇怪:为什么后置++必须返回一个const值?而不是像前置++一样返回引用就好了?
首先,返回值是因为这是个局部变量,一旦出了作用域,temp的生命周期就完结了,也就不存在引用了;其次,const 其实是在像”偶像”致敬。偶像?谁是偶像?int。
是的,当你不清楚你的实现应当跟谁保持一致的时候,去看看标准库里的数据类型,int类型支持++ ++ i,但是不支持i++ ++。所以,为了跟标准保持一致,建议像偶像看起。因此,返回const值也就说得通了。
最后,附上源码:
#include <iostream>
class complex
{
public:
complex& operator++()
{
a++;
b++;
return *this;
};
const complex operator++(int)
{
complex temp = *this;
++temp;
return temp;
};
int a = 0;
int b = 0;
};
std::ostream& operator<<(std::ostream& os, const complex& value)
{
os << value.a << " " << value.b << " ";
return os;
}
int main()
{
int a = 1;
int b = 1;
cout << "a: " << a << " 前++: " << ++a << " a:" << a << std::endl;
cout << "b: " << b << " 后++: " << b++ << " b:" << b << std::endl;
complex c;
cout << "c: " << c << " 前++++: " << ++ ++c << " 后++ " << c++ << std::endl;
return 0;
}
还没有评论,来说两句吧...