22。智能指针可能应该定义相等操作符和不等操作符,以便测试两个指针是否相等或不等。将这些操作加入到ScreenPtr类。 class ScreenPtr {
public: // … friend inline bool operator==( const ScreenPtr &, const ScreenPtr &); friend inline bool operator!=( const ScreenPtr &, const ScreenPtr &); private: ScrPtr *ptr; };
// operator ==
inline bool operator==( const ScreenPtr &p1, const ScreenPtr &p2 ) { return p1.ptr == p2.ptr; }
// operator !=
inline bool operator!=( const ScreenPtr &p1, const ScreenPtr &p2 ) { return !( p1.ptr == p2-.ptr ); }
23。CheckedPtr 类表示指向数组的指针。为该类重载下标操作符和解引用操作符。使操作符确保CheckedPtr有效:它应该不可能对超出数组末端的元素进行解引用或索引。 // 下标操作符重载
int& CheckedPtr::operator[]( const size_t index ) { if ( beg + index >= end ) throw out_ot_range( “ invalid index“ ); return *( beg + index ); }
const int & CheckedPtr::operator[] ( const size_t index ) const { if ( beg + index >= end ) throw out_ot_range( “ invalid index“ ); return *( beg + index ); }
// 解引用操作符重载 int CheckedPtr::operator*() { if ( curr == end )
throw out_of_range( “ invalid current pointer” ); return *curr; }
const int& CheckedPtr::operator*() const { if ( curr == end ) throw out_of_range(“ invalid current pointer”); return *curr; }
24。习题14.23中定义的解引用操作符或下标操作符,是否也应该检查对数组起点之前的元素进行的解引用或索引?解释你的答案。
对于下标操作符,应该进行检查,因为当用户给出的下标索引值小于0时,编译器不会出现编译错误,而会出现运行时错误。应修改为: // 下标操作符重载
int& CheckedPtr::operator[]( const size_t index ) { if ( beg + index >= end || beg + index < beg ) throw out_ot_range( “ invalid index“ ); return *( beg + index ); }
const int & CheckedPtr::operator[] ( const size_t index ) const { if ( beg + index >= end || beg + index < beg ) throw out_ot_range( “ invalid index“ ); return *( beg + index ); }
而对于解引用操作符,返回curr所指向的数组元素,在创建对象时已经将curr初始化为指向数组的第一个元素,只有当执行—操作时才会对curr进行减的操作,而—操作符已经对curr的值与数组起点进行了检查,所以不用再在这里检查。
25。为了表现得像数组指针,CheckedPtr类应实现相等和关系操作符,以便确定两个CheckedPtr对象是否相等,或者一个小于另一个,诸如此类。为CheckedPtr类增加这些操作。 应将这些操作符声明为CheckedPtr的友元。 // 相等操作符
bool operator==( const CheckedPtr& lhs, const CheckedPtr& rhs ) { return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr == rhs.curr; }
bool operator!=( const CheckedPtr & lhs, const CheckedPtr& rhs ) { return !( lhs == rhs ); }
// 关系操作符
bool operator<( const CheckedPtr & lhs, const CheckedPtr& rhs ) { return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr < rhs.curr; }
bool operator>( const CheckedPtr & lhs, const CheckedPtr& rhs ) { return lhs.beg == rhs.beg && lhs.end == rhs.end && lhs.curr > rhs.curr; }
bool operator<=( const CheckedPtr & lhs, const CheckedPtr& rhs ) { return !( lhs.curr > rhs.curr ); }
bool operator >=( const CheckedPtr & lhs, const CheckedPtr& rhs ) { return !( lhs.curr < rhs.curr ); }
26。为CheckedPtr类定义加法或减法,以便这些操作符实现指针运算。 将这两个操作符声明为类的友元。
CheckedPtr operator+( const CheckedPtr& lhs, const size_t n ) { CheckedPtr temp( lhs ); temp.curr += n; if ( temp.curr > temp.end ) throw out_of_range(“ Too large n, over.”); return temp; }
CheckedPtr operator-( const CheckedPtr& lhs, const size_t n ) { CheckedPtr temp( lhs ); temp.curr -= n; if ( temp.curr < temp.beg ) throw out_of_range(“ Too large n, over.”); return temp; }
用到了复制构造函数,定义为:
CheckedPtr::CheckedPtr( const CheckedPtr& cp ): beg( cp.beg ), end( cp.end ), curr( cp.curr ) { }
27。讨论允许将空数组实参传给CheckedPtr构造函数的优缺点。
优点:构造函数的定义简单。缺点:导致构造的对象没有指向有效的数组,从而失去使用价值。应该在构造函数里控制参数确保beg 28。没有定义自增和自减操作符的const版本,为什么? const所修饰的operator,不可以改变对象,而自增和自减肯定改变了对象,与const意义相反,所以不定义const版本。 29。我们也没有实现箭头操作符,为什么? 因为此类所指向的是int型数组,int型为内置类型,而箭头操作符必须返回一个类类型的指针,所以不实现。 30。定义一个CheckedPtr版本,保存Screen数组。为该类实现重载的自增、自减。解引用和箭头等操作符。 class CheckedPtr { public: CheckedPtr( Screen *b, Screen *e ): beg( b ), end( e ), curr( b ) { } // 自增、自减 CheckPtr& operator++(); CheckPtr& operator—(); CheckPtr& operator++( int ); CheckPtr& operator—( int ); // 箭头操作符 Screen* operator->(); const Screen* operator->() const; // 解引用操作 Screen& operator*(); const Screen& operator*(); private: Screen *beg; Screen *end; Screen *curr; }; CheckPtr& CheckPtr::operator++() { if ( curr == end ) throw out_of_range( “increment past the end of CheckedPtr”); ++curr; return *this; } CheckPtr& CheckPtr::operator—() { if ( curr == begin ) throw out_of_range( “decrement past the beginning of CheckedPtr”); --curr; return *this; } // 后缀式 CheckPtr& CheckPtr::operator++( int ) { CheckedPtr temp( *this ); ++*this; return temp; } CheckPtr& CheckPtr::operator—( int ) { CheckedPtr temp( *this ); --*this; return temp; } // 箭头操作符 Screen* CheckedPtr::operator->() { return curr; } const Screen* CheckedPtr::operator->() const { return curr; } Screen& CheckedPtr::operator*() { if ( curr == end ) throw out_of_range( “invalid current pointer.”); return *curr; } const Screen& CheckedPtr::operator*() const { if ( curr == end ) throw out_of_range( “invalid current pointer.”); return *curr; }