首页 > 代码库 > C++ Primer 学习笔记_61_重载操作符与转换 --自增/自减操作符
C++ Primer 学习笔记_61_重载操作符与转换 --自增/自减操作符
重载操作符与转换
--自增/自减操作符
引言:
自增,自减操作符常常由诸如迭代器这种类实现,这种类提供相似于指针的行为来訪问序列中的元素。比如,能够定义一个类,该类指向一个数组并为该数组中的元素提供訪问检查:
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; }
C++ Primer 学习笔记_61_重载操作符与转换 --自增/自减操作符