• C++学习笔记12:运算符重载(赋值操作符1)


    为数偶类定义专用的赋值操作符

    class Couple
    {
    public:
        Couple(int a = 0, int b = 0) :_a(a), _b(b) {}
        Couple(const Couple &c):_a(c._a),_b(c._b){}
        Couple &operator=(const Couple &c);
    private:
        int _a, _b;
    };
    
     Couple & Couple::operator=(const Couple &c)
    {
         if (*this == c)//在不同的情况下,此语句可能会降低程序的执行的效率,比如多数情况下赋值的不是对象自身,因此要根据情况判定;
         {
             return *this;
         }
        _a = c._a;
        _b = c._b;
        return *this;
    }
    
     int main()
     {
         Couple a(1, 2), b(2, 3);
         cout << a << endl;
         a = b;
         cout << a << endl;
         return 0;
    }

    为数偶类定义专用的简写四则运算符

    class Couple
    {
    public:
        Couple(int a = 0, int b = 0) :_a(a), _b(b) {}
        Couple(const Couple &c) :_a(c._a), _b(c._b) {}
        Couple &operator+=(const Couple &c);
        Couple &operator*=(const Couple &c);
        Couple &operator*=(const int &k);
    private:
        int _a, _b;
    };
    
    Couple & Couple::operator+=(const Couple &c)
    {
        _a += c._a;
        _b += c._b;
        return *this;
    }
    
    Couple & Couple::operator*=(const Couple &c)
    {
        _a *= c._a;
        _b *= c._b;
        return *this;
    }
    
    Couple & Couple::operator*=(const int &k)
    {
        _a *= k;
        _b *= k;
        return *this;
    }

    为数偶类定义专用的递增递减操作符

    class Couple
    {
    public:
        Couple(int a = 0, int b = 0) :_a(a), _b(b) {}
        Couple(const Couple &c) :_a(c._a), _b(c._b) {}
        Couple & operator=(const Couple &c);
        Couple & operator++();//前缀递增,返回本对象的引用
        Couple  operator++(int);//后缀递增,返回本对象的拷贝
    private:
        int _a, _b;
    };
    
    Couple & Couple::operator++()
    {
        ++_a, ++_b;
        return *this;
    }
    
    Couple Couple::operator++(int _t)
    {
        Couple _t(*this);
        _a++, _b++;
        return _t;
    }

    赋值操作符的返回值

    • 除后缀递增递减操作符,应返回对象的引用,以与C++本身的语义相符合
    • 返回对象需要额外的对象构造,降低效率
    • 如果不需要返回值以进行连续赋值,可以将返回值设为void,但要注意此时重载的操作符语义与C++不符合,故不推荐

    赋值构造与拷贝构造

    赋值也是构造

    拷贝、赋值与析构三位一体,一般同时出现

    • 缺省赋值构造与拷贝构造为浅拷贝
    • 如果对象没有指针成员,缺省行为即可满足要求,无需实现或重载这三个函数
    • 如果对象有指针成员,一般需要重载这三个函数

    浅拷贝

    class A
    {
    public:
        A():_n(0),_p(NULL){}
        explicit A(int n) :_n(n), _p(new int[n]) {}//把数组的基地址赋值给_p
        A(int n, int *p) :_n(n), _p(p) {}
        //如果省略以下语句,编译器自动生成以下两条语句(浅拷贝)
        A(const A & that) :_n(that._n), _p(that._p) {}//浅拷贝
        A & operator=(const A & that) { _n = that._n, _p = that._p; return *this; }
        virtual ~A() { if (_p) { delete[]_p; _p = NULL; } }
    public:
        int & operator[](int i);
        const int & operator[](int i) const;
    private:
        int _n;
        int *_p;
    };
    
    int & A::operator[](int i)
    {
        if (i < 0 || i >= 4)
            throw std::out_of_range("Out of range when trying to access the object... ");
        return _p[i];
    }
    
    const int & A::operator[](int i) const
    {
        if (i < 0 || i >= 4)
            throw std::out_of_range("Out of range when trying to access the object..");
        return _p[i];
    }
    
    int main()
    {
        A a(4), b;
        for ( int i = 0; i < 4; i++)
        {
            a[i] = i + 1;
        }
        std::cout << "Before object assignment:" << std::endl;
        for (int i = 0; i < 4; i++)
        {
            std::cout << a[i] << " ";
        }
        std::cout << std::endl;
        b = a;
        std::cout << "After object assignment:" << std::endl;
        for (int i = 0;  i < 4; i++)
        {
            std::cout << b[i] << " ";
        }
        std::cout << std::endl;
        return 0;//程序结束时,系统崩溃
    }

    对象a是main函数中定义的局部变量,当程序结束时对象a的_p会释放其指向的目标存储区,而对象b同样会去销毁目标存储区,但是目标存储区已被释放,此时出现了空悬指针;导致b在销毁对象使用delete[]时,程序崩溃;

     解决方法:

    • 使用深拷贝(拷贝一份指针指向目标数据对象的副本)

    class A
    {
    public:
        A():_n(0),_p(NULL){}
        explicit A(int n) :_n(n), _p(new int[n]) {}//把数组的基地址赋值给_p
        A(int n, int *p) :_n(n), _p(p) {}
        A(const A & that);
        A & operator=(const A & that);
        virtual ~A() { if (_p) { delete[]_p; _p = NULL; } }
    public:
        int & operator[](int i);
        const int & operator[](int i) const;
    private:
        int _n;
        int *_p;
    };
    
    A::A(const A & that)//拷贝构造函数
    {
        this->_n = that._n;
        _p = new int[_n];
        for (int i = 0;  i < _n;  i++)
        {
            _p[i] = that._p[i];
        }
    }
    
    A & A::operator=(const A & that)//重载赋值运算符
    {
        this->_n = that._n;
        if (_p)
        {
            delete[]_p;
        }
        _p = new int[_n];
        for (int i = 0; i < _n; i++)
        {
            _p[i] = that._p[i];
        }
        return *this;
    }

    注意:在赋值操作时本对象其实已经存在,_P可能指向一个有意义的数组,数组在赋值操作后即失去意义,所以要先删除_p指向的目标数组,然后对它进行创建连续的存储区,一个一个元素地拷贝;

    怕什么真理无穷,进一寸有一寸的欢喜。---胡适
  • 相关阅读:
    第二十四讲 ASP.NET中开发复合控件
    第二十六讲 使用ASP.NET实现网络通讯
    第二十五讲 ASP.NET中的XML
    【经验】android webview 后退键导致表单再次提交
    【笔记】java 泛型
    【笔记】Collection
    【算法】Tween算法
    【JavaSript】发现一个漏洞
    【研究】加载图片时,同一url,多次request
    【笔记】多态之Override
  • 原文地址:https://www.cnblogs.com/hujianglang/p/6219645.html
Copyright © 2020-2023  润新知