重载操作符与转换

--自增/自减操作符

引言:

自增,自减操作符常常由诸如迭代器这种类实现,这种类提供相似于指针的行为来訪问序列中的元素。比如,能够定义一个类,该类指向一个数组并为该数组中的元素提供訪问检查:

class CheckedPtr
{
public:
//这个类没有默认构造函数,必须提供指向数组的指针。
/**构造函数的參数是两个指针:一个指向数组的開始,还有一个指向数组的末端。
*构造函数用这两个指针初始化 beg 和 end
*并将 curr 初始化为指向第一个元素
*/
CheckedPtr(int *b,int *e):beg(b),end(e),curr(b){} private:
/**三个成员
*beg:指向数组的第一个元素;
*end:指向数组的末端;
*curr:指向 CheckedPtr 对象当前引用的数组元素。
*/
int *beg;
int *end;
int *curr;
};

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

【最佳实践】

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

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

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

class CheckedPtr
{
public:
CheckedPtr &operator++();
CheckedPtr &operator--();
//AS Before
};

【最佳实践】

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

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

CheckedPtr &CheckedPtr::operator++()
{
if (curr == end)
{
throw out_of_range("increment past the end of CheckedPtr");
}
++ curr; return *this;
} CheckedPtr &CheckedPtr::operator--()
{
if (curr == beg)
{
throw out_of_range("decrement past the beginning of CheckedPtr");
}
-- curr; return *this;
}

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

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

4、定义后缀式操作符

class CheckedPtr
{
public:
CheckedPtr &operator++(int);
CheckedPtr &operator--(int);
//AS Before
};

【最佳实践】

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

CheckedPtr CheckedPtr::operator++(int)
{
CheckedPtr ret(*this);
++ *this; return ret;
} CheckedPtr CheckedPtr::operator--(int)
{
CheckedPtr ret(*this);
-- *this; return ret;
}

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

++*this;	//-- *this;

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

   因为不使用int形參,所以对其没有命名

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

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

    CheckedPtr parr(ia,ia+ sizeof(ia)/sizeof(*ia));
parr.operator++(); //显式调用前缀式
parr.operator++(0); //显式调用后缀式

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

【最佳实践】

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

//P449 习题14.23~26 着反复习前面几节的知识,因为知识点都比較简单,所以差点儿没有凝视...
#include <iostream>
#include <stdexcept>
using namespace std; class CheckedPtr
{
friend bool operator==(const CheckedPtr &lhs,const CheckedPtr &rhs);
friend bool operator<(const CheckedPtr &lhs,const CheckedPtr &rhs);
friend bool operator>(const CheckedPtr &lhs,const CheckedPtr &rhs); friend CheckedPtr operator+(const CheckedPtr &lhs,const size_t n);
friend CheckedPtr operator-(const CheckedPtr &lhs,const size_t n);
friend ptrdiff_t operator-(const CheckedPtr &lhs,const CheckedPtr &rhs); public:
CheckedPtr(int *b,int *e):beg(b),end(e),curr(b) {} CheckedPtr &operator++();
CheckedPtr &operator--(); CheckedPtr operator++(int);
CheckedPtr operator--(int); int &operator[] (const size_t);
const int &operator[] (const size_t) const; int &operator*();
const int &operator*() const; private:
int *beg;
int *end;
int *curr;
}; CheckedPtr operator+(const CheckedPtr &rhs,const size_t n)
{
CheckedPtr ret(rhs);
ret.curr += n;
if (ret .curr > ret.end)
{
throw out_of_range("operator + out_of_range!");
} return ret;
} CheckedPtr operator-(const CheckedPtr &rhs,const size_t n)
{
CheckedPtr ret(rhs);
ret.curr -= n;
if (ret.curr < ret.beg)
{
throw out_of_range("operator - out_of_range!");
} return ret;
} ptrdiff_t operator-(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
if (!(lhs.beg == rhs.beg && lhs.end == rhs.end))
{
throw out_of_range("operator - out_of_range!");
} return lhs.curr - rhs.curr;
} inline
bool operator==(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return lhs.beg == rhs.beg && lhs.curr == rhs.curr && lhs.end == rhs.end;
}
inline
bool operator!=(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return !(lhs == rhs);
} inline
bool operator<(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr < rhs.curr;
}
inline
bool operator>=(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return !(lhs < rhs);
} inline
bool operator>(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr > rhs.curr;
}
inline
bool operator<=(const CheckedPtr &lhs,const CheckedPtr &rhs)
{
return !(lhs > rhs);
//OR: return lhs == rhs || lhs < rhs;
} int &CheckedPtr::operator*()
{
if (curr == end)
{
throw out_of_range("Error Pointer!");
} return *curr;
} const int &CheckedPtr::operator*() const
{
if (curr == end)
{
throw out_of_range("Error Pointer!");
} return *curr;
} int &CheckedPtr::operator[](const size_t index)
{
if (beg + index >= end || beg + index < beg)
{
throw out_of_range("index: out_of_range!");
}
return *(beg + index);
} const int &CheckedPtr::operator[](const size_t index) const
{
if (beg + index >= end || beg + index < beg)
{
throw out_of_range("index: out_of_range!");
} return *(beg + index);
} CheckedPtr &CheckedPtr::operator++()
{
if (curr == end)
{
throw out_of_range("increment past the end of CheckedPtr");
}
++ curr; return *this;
} CheckedPtr &CheckedPtr::operator--()
{
if (curr == beg)
{
throw out_of_range("decrement past the beginning of CheckedPtr");
}
-- curr; return *this;
} CheckedPtr CheckedPtr::operator++(int)
{
CheckedPtr ret(*this);
++ *this; return ret;
} CheckedPtr CheckedPtr::operator--(int)
{
CheckedPtr ret(*this);
-- *this; return ret;
} //測试
int main()
{
int ia[] = {10,8,6,4,2,0};
CheckedPtr flag(ia,ia + sizeof(ia)/sizeof(*ia)); for (CheckedPtr parr(ia,ia + sizeof(ia)/sizeof(*ia));
parr != flag + sizeof(ia)/sizeof(*ia); parr = parr + 2)
{
cout << *parr << endl;
} for (CheckedPtr parr(ia,ia + sizeof(ia)/sizeof(*ia));
parr != flag + sizeof(ia)/sizeof(*ia); ++ parr)
{
cout << *parr << endl;
} CheckedPtr parr1(ia,ia + sizeof(ia)/sizeof(*ia));
cout << endl << parr1[2] << endl;
cout << *parr1 << endl; CheckedPtr parr2(ia,ia + sizeof(ia)/sizeof(*ia));
++ parr2;
cout << "parr1 <= parr2 ? " << (parr1 <= parr2) << endl; return 0;
}

最新文章

  1. Group by
  2. jfinal 解决ajax 跨域访问--jsonp
  3. 在C代码中调用C++接口
  4. win7/8下VirtualBox虚拟Ubuntu共享文件夹设置
  5. Delphi操作XML的几个博客
  6. Linux平台Cpu使用率的计算
  7. centos 没有可用的网络设备
  8. ScrollView嵌套ListView嵌套GridView的上下拉以及加载更多
  9. highcharts 结合phantomjs纯后台生成图片系列二之php2
  10. hadoop-1.1.2集群搭建
  11. jQuery中的经典动画
  12. Tornado,表单处理,一样在行
  13. .Net程序员快速学习安卓开发-布局和点击事件的写法
  14. C#泛型理解(转)
  15. 001.MVC基本概述
  16. 几张图带你轻轻松松了解小程序和APP的区别
  17. java.security.InvalidKeyException: Illegal key size
  18. appium测试准备记录
  19. SVN汉化教程2017.10.6
  20. lr-web services协议

热门文章

  1. Ember.js - About
  2. Android 讲述Help提示框
  3. Objective-C中的SEL、IMP和Class类型
  4. 以交互方式使用exp/imp的演示
  5. 聊天气泡的绘制(圆角矩形+三角形+黑色边框,关键学会QPainter的draw函数就行了),注意每个QLabel都有自己的独立坐标
  6. asp.net中通过注册表来检测是否安装Office(迅雷/QQ是否已安装)
  7. J2EE SSH学习(二)安装Eclipse插件和第一个Eclipse项目
  8. 微凉大大,教你一步一步在linux中正确的安装Xcache加速php。
  9. 打印org.eclipse.xsd.XSDSchema对象
  10. 基于MMSeg算法的中文分词类库