pe14_26_2.cpp//dui 26题的优化
适当的const保护,还有操作符函数的定义顺序最好遵从声明顺序,看起来清晰一点
#include"head.h" //版本二,优化加减法判断问题,我要把加负数的情况直接转化为调用减法,反之相反 //调用相反操作符时传递参数要注意,传入(0 - change)有个转化 class CheckedPtr{ public: CheckedPtr(int* b, int* e): beg(b), end(e), curr(b) {} public: CheckedPtr& operator++(); CheckedPtr& operator--(); //添加一个没用的形参,来实现重载,此外,可以利用这个显式调用后缀操作,注意后缀返回的是原副本 CheckedPtr operator++(int); CheckedPtr operator--(int); int& operator*(); int& operator[](unsigned); bool operator<(const CheckedPtr&);//为该类增加这些操作:指的是成员函数把? bool operator==(const CheckedPtr&); //加减数字来调整指针指向,返回一个副本,指向新位置 CheckedPtr operator+(int); CheckedPtr operator-(int); public: int getCurr(){return *curr;} private: int* beg; int* end; int* curr; }; CheckedPtr& CheckedPtr::operator++(){ if(curr == end) throw std::out_of_range//<stdexcept>,之前那些都不能用,今次能用了啊,(可能catch之类的还是不行把,那块跳过了) ("increment past the end of CheckedPtr"); ++curr; return *this; } CheckedPtr& CheckedPtr::operator--(){ if(curr == beg) throw std::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& CheckedPtr::operator*(){ if(curr > end || curr < beg) throw std::out_of_range ("out of range~!"); return *curr; } int& CheckedPtr::operator[](unsigned index){ if(index >= (end - beg) || index < 0) throw std::out_of_range ("out of range~!"); int * temp = curr;//需要对原位置进行一个保护 curr = beg;//重置curr,保证每次都是从0计算,得到正确下标 for(unsigned i = 0; i < index; i++) curr++; int* ret = curr; std::cout << "test\t*curr: " << *curr << std::endl; curr = temp;//还原curr std::cout << "test\t*curr: " << *curr << std::endl; return *ret;//既要保护原curr位置,在返回前还原,又要返回引用供修改,我认为办不到。。。。。。。。。。。。。。 //I did it~!!!!!!!!!!!!!!!1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 } bool CheckedPtr::operator<(const CheckedPtr& rhs){ if((curr - beg) < (rhs.curr - rhs.beg)) return 1; return 0; } bool CheckedPtr::operator==(const CheckedPtr& rhs){ if((curr - beg) == (rhs.curr - rhs.beg)) return 1; return 0; } //两指针相加有什么意义 //(lhs.curr - lhs.beg) + (rhs.curr - rhs.beg) - lhs.beg; //太麻烦了 //int operator+(const CheckedPtr& lhs, const CheckedPtr& rhs){ /*指针减,返回差值,可以是正负,前提也是同一数组 int operator-(const CheckedPtr& lhs, const CheckedPtr& rhs){ return (lhs.curr - rhs.curr);//private,还要定义成成员 } * 意义不大,还是用指针加减数字有用 */ CheckedPtr CheckedPtr::operator+(const int change){//不限制正负号会比较麻烦,只为满足 ptr + (-10);这种操作 if(change < 0){ CheckedPtr ret = this->operator-(0 - change); return ret; } else{ if((curr + change) < beg || (curr + change) >= end)//还要判断出界问题 throw std::out_of_range ("out of range"); CheckedPtr ret(beg, end); ret.curr = curr;//必要:不然加法不具备累积性,ptr + 1; ptr + 2;总共算+2 if(change >= 0) for(int i = 0; i < change; i++) ret++; return ret; } } CheckedPtr CheckedPtr::operator-(const int change){//不限制正负号会比较麻烦,只为满足 ptr - (-10);这种操作 if(change < 0){ CheckedPtr ret = this->operator+(0 - change); return ret; } else{ if((curr - change) < beg || (curr - change) >= end)//还要判断出界问题 throw std::out_of_range ("out of range"); CheckedPtr ret(beg, end); ret.curr = curr;//必要:不然加法不具备累积性,ptr + 1; ptr + 2;总共算+2 for(int i = 0; i < change; i++) ret--; return ret; } } int main(){ const unsigned size = 10; int a[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; CheckedPtr ptr1(a, a + size); CheckedPtr ptr2(a, a + size); //测试加法 std::cout << *ptr2 << std::endl; ptr2 = ptr2 + 3; std::cout << "after ptr2 + 3 : " << *ptr2 << std::endl; ptr2 = ptr2 + 4; std::cout << "after ptr2 + 4 : " << *ptr2 << std::endl; ptr2 = ptr2 + (-1);//加负数,另一种思路是用判断条件,如果有加负数,直接调用减法操作符,有待添加(已修改) std::cout << "after ptr2 + (-1) : " << *ptr2 << std::endl; ptr2 = ptr2 - 1; std::cout << "after ptr2 - 1 : " << *ptr2 << std::endl; ptr2 = ptr2 - (-1);//减负数,另一种思路是用判断条件,如果有减负数,直接调用加法操作符,有待添加(已修改) std::cout << "after ptr2 - (-1) : " << *ptr2 << std::endl; //ptr2 - (-2);//越上界 //ptr2 = ptr1 + 11;//测试越界 //ptr }
14.24
下标和解引用是否需要对数组起点之前的元素进行检查,下标不用,我传的是unsigned,从0开始,解引用就更不用了,因为整个类对象已经有了curr的越界检查,所以对象不能有超界状态。
14.27
允许构造函数传入数组实参,缺点是边界判断,相比(beg, end),传入数组没有end,不过可以用size()自己去判断吧(状态不佳,扔着了)
14.28没定义自增和自减操作符的const版本,为什么
因为要改变成员curr,不同于一般意义的指针自加自减
14.29
为什么不实现箭头操作符
怕理解不便吧,需要的箭头操作是取数组的某元素吧,箭头操作符也可以是取对象的成员,引起误解
14.30再定义一个CheckedPtr版本,保存Screen数组,为该类实现重载的自增、自减、解引用、箭头等操作。
#include"head.h" //保存Screen数组用,并定义各种操作 class Screen{ public: typedef std::string::size_type index;//利用typedef char get() const{ //return contents[cursor]; return 'T';//test }//重载 void setTest(index i = 1){cursor = i;} index getTest(){return cursor;} inline char get(index ht, index wd) const;//显式定义inline index get_cursor() const;//后者便于阅读,在类的定义里的声明比较清晰 public: Screen(index ht, index wd): height(ht), width(wd) {} Screen(): height(0), width(0) {} private: std::string contents; index cursor;//光标 index height, width;//同时声明多个 }; class CheckedPtr{ public: CheckedPtr(Screen* b, Screen* e): beg(b), end(e), curr(b) {} public: CheckedPtr& operator++(); CheckedPtr& operator--(); //添加一个没用的形参,来实现重载,此外,可以利用这个显式调用后缀操作,注意后缀返回的是原副本 CheckedPtr operator++(int); CheckedPtr operator--(int); Screen& operator*(); Screen& operator[](unsigned); bool operator<(const CheckedPtr&);//为该类增加这些操作:指的是成员函数把? bool operator==(const CheckedPtr&); //加减数字来调整指针指向,返回一个副本,指向新位置 CheckedPtr operator+(int); CheckedPtr operator-(int); public: Screen getCurr(){return *curr;} private: Screen* beg; Screen* end; Screen* curr; }; CheckedPtr& CheckedPtr::operator++(){ if(curr == end) throw std::out_of_range//<stdexcept>,之前那些都不能用,今次能用了啊,(可能catch之类的还是不行把,那块跳过了) ("increment past the end of CheckedPtr"); ++curr; return *this; } CheckedPtr& CheckedPtr::operator--(){ if(curr == beg) throw std::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; } Screen& CheckedPtr::operator*(){ if(curr > end || curr < beg) throw std::out_of_range ("out of range~!"); return *curr; } Screen& CheckedPtr::operator[](unsigned index){ if(index >= (end - beg) || index < 0) throw std::out_of_range ("out of range~!"); Screen * temp = curr;//需要对原位置进行一个保护 curr = beg;//重置curr,保证每次都是从0计算,得到正确下标 for(unsigned i = 0; i < index; i++) curr++; Screen* ret = curr; std::cout << "test\t*curr: " << curr->getTest() << std::endl; curr = temp;//还原curr std::cout << "test\t*curr: " << curr->getTest() << std::endl; return *ret; } bool CheckedPtr::operator<(const CheckedPtr& rhs){ if((curr - beg) < (rhs.curr - rhs.beg)) return 1; return 0; } bool CheckedPtr::operator==(const CheckedPtr& rhs){ if((curr - beg) == (rhs.curr - rhs.beg)) return 1; return 0; } //两指针相加有什么意义 //(lhs.curr - lhs.beg) + (rhs.curr - rhs.beg) - lhs.beg; //太麻烦了 //int operator+(const CheckedPtr& lhs, const CheckedPtr& rhs){ /*指针减,返回差值,可以是正负,前提也是同一数组 int operator-(const CheckedPtr& lhs, const CheckedPtr& rhs){ return (lhs.curr - rhs.curr);//private,还要定义成成员 } * 意义不大,还是用指针加减数字有用 */ CheckedPtr CheckedPtr::operator+(const int change){//不限制正负号会比较麻烦,只为满足 ptr + (-10);这种操作 if(change < 0){ CheckedPtr ret = this->operator-(0 - change); return ret; } else{ if((curr + change) < beg || (curr + change) >= end)//还要判断出界问题 throw std::out_of_range ("out of range"); CheckedPtr ret(beg, end); ret.curr = curr;//必要:不然加法不具备累积性,ptr + 1; ptr + 2;总共算+2 if(change >= 0) for(int i = 0; i < change; i++) ret++; return ret; } } CheckedPtr CheckedPtr::operator-(const int change){//不限制正负号会比较麻烦,只为满足 ptr - (-10);这种操作 if(change < 0){ CheckedPtr ret = this->operator+(0 - change); return ret; } else{ if((curr - change) < beg || (curr - change) >= end)//还要判断出界问题 throw std::out_of_range ("out of range"); CheckedPtr ret(beg, end); ret.curr = curr;//必要:不然加法不具备累积性,ptr + 1; ptr + 2;总共算+2 for(int i = 0; i < change; i++) ret--; return ret; } } int main(){ const unsigned size = 10; Screen s[size]; s[1].setTest(8); std::cout << s[1].getTest() << std::endl; CheckedPtr ptr(s, s + size - 1); std::cout << (*++ptr).getTest() << std::endl; std::cout << (*++ptr).getTest() << std::endl; std::cout << ptr[5].getTest() << std::endl; }