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;
}