C++(28)自增/自减操作符

重载操作符与转换

--自增/自减操作符



引言:

    自增,自减操作符经常由诸如迭代器这样的类实现,这样的类提供类似于指针的行为来访问序列中的元素。例如,可以定义一个类,该类指向一个数组并为该数组中的元素提供访问检查:


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class CheckedPtr  
  2. {  
  3. public:  
  4.     //这个类没有默认构造函数,必须提供指向数组的指针。  
  5.     /**构造函数的参数是两个指针:一个指向数组的开始,另一个指向数组的末端。 
  6.     *构造函数用这两个指针初始化 beg 和 end 
  7.     *并将 curr 初始化为指向第一个元素 
  8.     */  
  9.     CheckedPtr(int *b,int *e):beg(b),end(e),curr(b){}  
  10.   
  11. private:  
  12.     /**三个成员 
  13.     *beg:指向数组的第一个元素; 
  14.     *end:指向数组的末端; 
  15.     *curr:指向 CheckedPtr 对象当前引用的数组元素。 
  16.     */  
  17.     int *beg;  
  18.     int *end;  
  19.     int *curr;  
  20. };  

1、定义自增/自减操作符

【最佳实践】

    C++语言不要求自增/自减操作符一定作为类的成员,但是,因为这些操作符改变操作对象的状态,所以更倾向于将它们作为成员


2、定义前自增/自减操作符

    前缀式操作符的声明看起来像这样:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class CheckedPtr  
  2. {  
  3. public:  
  4.     CheckedPtr &operator++();  
  5.     CheckedPtr &operator--();  
  6. //AS Before  
  7. };  

【最佳实践】

     为了与内置类型一致,前缀操作符应该返回被增量或减量对象的引用

    自增操作符根据end检查curr,从而确保用户不能将curr增加到超过数组的末端。自减操作将curr减 1并检查是否会减到beg,如果curr增量到超过endcurr自减超过 beg就抛出一个out_of_range异常:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CheckedPtr &CheckedPtr::operator++()  
  2. {  
  3.     if (curr == end)  
  4.     {  
  5.         throw out_of_range("increment past the end of CheckedPtr");  
  6.     }  
  7.     ++ curr;  
  8.   
  9.     return *this;  
  10. }  
  11.   
  12. CheckedPtr &CheckedPtr::operator--()  
  13. {  
  14.     if (curr == beg)  
  15.     {  
  16.         throw out_of_range("decrement past the beginning of CheckedPtr");  
  17.     }  
  18.     -- curr;  
  19.   
  20.     return *this;  
  21. }  

3、区别操作符的前缀和后缀形式

    后缀式操作符函数接受一个额外的(即:无用的)int型形参。使用后缀式操作符时,编译器提供0作为这个形参的实参。这个int形参的唯一目的就是使后缀函数与前缀函数区别开来


4、定义后缀式操作符

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class CheckedPtr  
  2. {  
  3. public:  
  4.     CheckedPtr &operator++(int);  
  5.     CheckedPtr &operator--(int);  
  6. //AS Before  
  7. };  

【最佳实践】

      为了与内置操作符一致,后缀式操作符应返回旧值[即:尚未自增或自减的值],并且,应作为值返回,而不是引用!


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CheckedPtr CheckedPtr::operator++(int)  
  2. {  
  3.     CheckedPtr ret(*this);  
  4.     ++ *this;  
  5.   
  6.     return ret;  
  7. }  
  8.   
  9. CheckedPtr CheckedPtr::operator--(int)  
  10. {  
  11.     CheckedPtr ret(*this);  
  12.     -- *this;  
  13.   
  14.     return ret;  
  15. }  

   必须保存对象在加1/1之前的当前状态,当保存了当前状态的副本之后,操作符调用自己的前缀式操作符分别进行加1/1:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ++*this;    //-- *this;  

   调用这个对象自己的已经定义好了的前缀自增/自减操作符,那些关于curr是否处在begend范围之内的检查,以及是否抛出异常,则由它们代劳了O(∩_∩)O

   由于不使用int形参,所以对其没有命名


5、显式调用自增/自减操作符

   如果想要使用函数调用来调用后缀式操作符,必须给出一个整型实参值:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CheckedPtr parr(ia,ia+ sizeof(ia)/sizeof(*ia));  
  2. parr.operator++();  //显式调用前缀式  
  3. parr.operator++(0); //显式调用后缀式  

所传的值通常被忽略,但是该值是必要的,用于通知编译器需要的是后缀式版本!

【最佳实践】

    一般而言,最好前缀式和后缀式都定义,只定义前缀式或只定义后缀式的类,将会让习惯于使用两种形式的用户感到奇怪。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //P449 习题14.23~26 着重复习前面几节的知识,由于知识点都比较简单,所以几乎没有注释...  
  2. #include <iostream>  
  3. #include <stdexcept>  
  4. using namespace std;  
  5.   
  6. class CheckedPtr  
  7. {  
  8.     friend bool operator==(const CheckedPtr &lhs,const CheckedPtr &rhs);  
  9.     friend bool operator<(const CheckedPtr &lhs,const CheckedPtr &rhs);  
  10.     friend bool operator>(const CheckedPtr &lhs,const CheckedPtr &rhs);  
  11.   
  12.     friend CheckedPtr operator+(const CheckedPtr &lhs,const size_t n);  
  13.     friend CheckedPtr operator-(const CheckedPtr &lhs,const size_t n);  
  14.     friend ptrdiff_t operator-(const CheckedPtr &lhs,const CheckedPtr &rhs);  
  15.   
  16. public:  
  17.     CheckedPtr(int *b,int *e):beg(b),end(e),curr(b) {}  
  18.   
  19.     CheckedPtr &operator++();  
  20.     CheckedPtr &operator--();  
  21.   
  22.     CheckedPtr operator++(int);  
  23.     CheckedPtr operator--(int);  
  24.   
  25.     int &operator[] (const size_t);  
  26.     const int &operator[] (const size_tconst;  
  27.   
  28.     int &operator*();  
  29.     const int &operator*() const;  
  30.   
  31.   
  32. private:  
  33.     int *beg;  
  34.     int *end;  
  35.     int *curr;  
  36. };  
  37.   
  38. CheckedPtr operator+(const CheckedPtr &rhs,const size_t n)  
  39. {  
  40.     CheckedPtr ret(rhs);  
  41.     ret.curr += n;  
  42.     if (ret .curr > ret.end)  
  43.     {  
  44.         throw out_of_range("operator + out_of_range!");  
  45.     }  
  46.   
  47.     return ret;  
  48. }  
  49.   
  50. CheckedPtr operator-(const CheckedPtr &rhs,const size_t n)  
  51. {  
  52.     CheckedPtr ret(rhs);  
  53.     ret.curr -= n;  
  54.     if (ret.curr < ret.beg)  
  55.     {  
  56.         throw out_of_range("operator - out_of_range!");  
  57.     }  
  58.   
  59.     return ret;  
  60. }  
  61.   
  62. ptrdiff_t operator-(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  63. {  
  64.     if (!(lhs.beg == rhs.beg && lhs.end == rhs.end))  
  65.     {  
  66.         throw out_of_range("operator - out_of_range!");  
  67.     }  
  68.   
  69.     return lhs.curr - rhs.curr;  
  70. }  
  71.   
  72. inline  
  73. bool operator==(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  74. {  
  75.     return lhs.beg == rhs.beg && lhs.curr == rhs.curr && lhs.end == rhs.end;  
  76. }  
  77. inline  
  78. bool operator!=(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  79. {  
  80.     return !(lhs == rhs);  
  81. }  
  82.   
  83. inline  
  84. bool operator<(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  85. {  
  86.     return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr < rhs.curr;  
  87. }  
  88. inline  
  89. bool operator>=(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  90. {  
  91.     return !(lhs < rhs);  
  92. }  
  93.   
  94. inline  
  95. bool operator>(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  96. {  
  97.     return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr > rhs.curr;  
  98. }  
  99. inline  
  100. bool operator<=(const CheckedPtr &lhs,const CheckedPtr &rhs)  
  101. {  
  102.     return !(lhs > rhs);  
  103.     //OR: return lhs == rhs || lhs < rhs;  
  104. }  
  105.   
  106. int &CheckedPtr::operator*()  
  107. {  
  108.     if (curr == end)  
  109.     {  
  110.         throw out_of_range("Error Pointer!");  
  111.     }  
  112.   
  113.     return *curr;  
  114. }  
  115.   
  116. const int &CheckedPtr::operator*() const  
  117. {  
  118.     if (curr == end)  
  119.     {  
  120.         throw out_of_range("Error Pointer!");  
  121.     }  
  122.   
  123.     return *curr;  
  124. }  
  125.   
  126. int &CheckedPtr::operator[](const size_t index)  
  127. {  
  128.     if (beg + index >= end || beg + index < beg)  
  129.     {  
  130.         throw out_of_range("index: out_of_range!");  
  131.     }  
  132.     return *(beg + index);  
  133. }  
  134.   
  135. const int &CheckedPtr::operator[](const size_t index) const  
  136. {  
  137.     if (beg + index >= end || beg + index < beg)  
  138.     {  
  139.         throw out_of_range("index: out_of_range!");  
  140.     }  
  141.   
  142.     return *(beg + index);  
  143. }  
  144.   
  145. CheckedPtr &CheckedPtr::operator++()  
  146. {  
  147.     if (curr == end)  
  148.     {  
  149.         throw out_of_range("increment past the end of CheckedPtr");  
  150.     }  
  151.     ++ curr;  
  152.   
  153.     return *this;  
  154. }  
  155.   
  156. CheckedPtr &CheckedPtr::operator--()  
  157. {  
  158.     if (curr == beg)  
  159.     {  
  160.         throw out_of_range("decrement past the beginning of CheckedPtr");  
  161.     }  
  162.     -- curr;  
  163.   
  164.     return *this;  
  165. }  
  166.   
  167. CheckedPtr CheckedPtr::operator++(int)  
  168. {  
  169.     CheckedPtr ret(*this);  
  170.     ++ *this;  
  171.   
  172.     return ret;  
  173. }  
  174.   
  175. CheckedPtr CheckedPtr::operator--(int)  
  176. {  
  177.     CheckedPtr ret(*this);  
  178.     -- *this;  
  179.   
  180.     return ret;  
  181. }  
  182.   
  183. //测试  
  184. int main()  
  185. {  
  186.     int ia[] = {10,8,6,4,2,0};  
  187.     CheckedPtr flag(ia,ia + sizeof(ia)/sizeof(*ia));  
  188.   
  189.     for (CheckedPtr parr(ia,ia + sizeof(ia)/sizeof(*ia));  
  190.             parr != flag + sizeof(ia)/sizeof(*ia); parr = parr + 2)  
  191.     {  
  192.         cout << *parr << endl;  
  193.     }  
  194.   
  195.     for (CheckedPtr parr(ia,ia + sizeof(ia)/sizeof(*ia));  
  196.             parr != flag + sizeof(ia)/sizeof(*ia); ++ parr)  
  197.     {  
  198.         cout << *parr << endl;  
  199.     }  
  200.   
  201.     CheckedPtr parr1(ia,ia + sizeof(ia)/sizeof(*ia));  
  202.     cout << endl << parr1[2] << endl;  
  203.     cout << *parr1 << endl;  
  204.   
  205.     CheckedPtr parr2(ia,ia + sizeof(ia)/sizeof(*ia));  
  206.     ++ parr2;  
  207.     cout << "parr1 <= parr2 ? " << (parr1 <= parr2) << endl;  
  208.   
  209.     return 0;  
  210. }  

转载于:https://my.oschina.net/sfsimon/blog/659287

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值