• 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添加到超过数组的末端。自减操作将curr1并检查是否会减到beg,假设curr增量到超过endcurr自减超过 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是否处在begend范围之内的检查,以及是否抛出异常,则由它们代劳了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;
    }

  • 相关阅读:
    Docker容器管理神器
    查看MySQL连接状态
    使用 Docker 镜像安装 Radicale3
    Java文档注释的使用
    Hibernate依赖问题
    WPF HelixToolkit 3D
    二分法
    比较 React vue, 单向绑定 双向绑定 优缺点
    7 个杀手级的 JS 一行代码
    js中??和?.的意思
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3930072.html
Copyright © 2020-2023  润新知