副标题#e#
好久以前(八十年月),没有步伐区分++和–操纵符的前缀与后缀挪用。这个问题遭到措施员的报怨,于是C++语言获得了扩展,答允重载increment 和 decrement操纵符的两种形式。
然而有一个句法上的问题,重载函数间的区别抉择于它们的参数范例上的差别,可是岂论是increment或decrement的前缀照旧后缀都只有一个参数。为了办理这个语言问题,C++划定后缀形式有一个int范例参数,当函数被挪用时,编译器通报一个0做为int参数的值给该函数:
class UPInt { // "unlimited precision int"
public:
UPInt& operator++(); // ++ 前缀
const UPInt operator++(int); // ++ 后缀
UPInt& operator--(); // -- 前缀
const UPInt operator--(int); // -- 后缀
UPInt& operator+=(int); // += 操纵符,UPInts
// 与ints 相运算
...
};
UPInt i;
++i; // 挪用 i.operator++();
i++; // 挪用 i.operator++(0);
--i; // 挪用 i.operator--();
i--; // 挪用 i.operator--(0);
这个类型有一些离奇,不外你会习惯的。而尤其要留意的是这些操纵符前缀与后缀形式返回值范例是差异的。前缀形式返回一个引用,后缀形式返回一个const范例。下面我们将接头++操纵符的前缀与后缀形式,这些说明也同样利用与–操纵符。
从你开始做C措施员那天开始,你就记着increment的前缀形式有时叫做“增加然后取回”,后缀形式叫做“取回然后增加”。这两句话很是重要,因为它们是increment前缀与后缀的形式上的类型。
// 前缀形式:增加然后取回值
UPInt& UPInt::operator++()
{
*this += 1; // 增加
return *this; // 取回值
}
// postfix form: fetch and increment
const UPInt UPInt::operator++(int)
{
UPInt oldValue = *this; // 取回值
++(*this); // 增加
return oldValue; // 返回被取回的值
}
后缀操纵符函数没有利用它的参数。它的参数只是用来区分前缀与后缀函数挪用。假如你没有在函数里利用参数,很多编译器会显示告诫信息,很令人讨厌。为了制止这些告诫信息,一种常常利用的要领时省略掉你不想利用的参数名称;如上所示。
#p#副标题#e#
很明明一个后缀increment必需返回一个工具(它返回的是增加前的值),可是为什么是const工具呢?假设不是const工具,下面的代码就是正确的:
UPInt i;
i++++; // 两次increment后缀
// 运算
这组代码与下面的代码沟通:
i.operator++(0).operator++(0);
很明明,第一个挪用的operator++函数返回的工具挪用了第二个operator++函数。
有两个来由导致我们应该厌恶上述这种做法,第一是与内置范例行为纷歧致。当设计一个类碰着问题时,一个好的准则是使该类的行为与int范例一致。而int范例不答允持续举办两次后缀increment:
int i;
i++++; // 错误!
第二个原因是利用两次后缀increment所发生的功效与挪用者期望的纷歧致。如上所示,第二次挪用operator++改变的值是第一次挪用返回工具的值,而不是原始工具的值。因此假如:
i++++;
是正当的,i将仅仅增加了一次。这与人的直觉相违背,使人疑惑(对付int范例和UPInt都是一样),所以最好克制这么做。
C++克制int范例这么做,同时你也必需克制你本身写的类有这样的行为。最容易的要领是让后缀increment 返回const工具。当编译器碰着这样的代码:
i++++; // same as i.operator++(0).operator++(0);
它发明从第一个operator++函数返回的const工具又挪用operator++函数,然而这个函数是一个non-const成员函数,所以const工具不能挪用这个函数。假如你本来想过让一个函数返回const工具没有任何意义,此刻你就知道有时照旧有用的,后缀increment和decrement就是例子。(更多的例子拜见Effective C++ 条款21)
假如你很体贴效率问题,当你第一次看到后缀increment函数时, 你大概以为有些问题。这个函数必需成立一个姑且工具以做为它的返回值,(拜见条款19),上述实现代码成立了一个显示的姑且工具(oldValue),这个姑且工具必需被结构并在最后被布局。前缀increment函数没有这样的姑且工具。由此得出一个令人惊奇的结论,假如仅为了提高代码效率,UPInt的挪用者应该只管利用前缀increment,罕用后缀increment,除非确实需要利用后缀increment。让我们明晰一下,当处理惩罚用户界说的范例时,尽大概地利用前缀increment,因为它的效率较高。
我们再调查一下后缀与前缀increment 操纵符。它们除了返回值差异外,所完成的成果是一样的,即值加一。简而言之,它们被认为成果一样。那么你如何确保后缀increment和前缀increment的行为一致呢?当差异的措施员去维护和进级代码时,有什么能担保它们不会发生差别?除非你遵守上述代码里的原则,这才气获得确保。这个原则是后缀increment和decrement应该按照它们的前缀形式来实现。你仅仅需要维护前缀版本,因为后缀形式自动与前缀形式的行为一致。
#p#分页标题#e#
正如你所看到的,把握前缀和后缀increment和decrement是容易的。一旦相识了他们正确的返回值范例以及后缀操纵符应该以前缀操纵符为基本来实现的法则,就足够了。