• 操作符重载(一)


    一,运算符重载的基础知识

    1.什么是运算符重载

      所谓的重载,就是重新赋予新的含义。函数的重载是让一个已经存在的函数赋予一个新的含义,使之实现新的功能。因此,一个函数名就可以用来代表不同功能的函数。运算符的重载其实我们已经使用过了,例如常见的"+"加法操作就是C++默认重载的,我们可以用加法对整数,单精度,双精度的数据进行加法运算,也是一个运算符可以有不同的功能。C++还为我们提供了自己进行运算符重载的方式。

    2.运算符重载的推演

      我们可以自然而然的使用“+”号对两个整数或者浮点数进行求和运算,但是如果是复数呢,我们就不能简单的用“+”号来进行操作,就必须要用函数来进行两个复数的操作,下面来进行运算符重载的推演。

    3.运算符重载推演代码的实现

    # include<iostream>
    using namespace std;
    
    /* 定义复数类 */
    class Complex
    {
    private:
        int a;
        int b;
        friend Complex& operator+(Complex& c1, Complex& c2);
    public:
        Complex(int a, int b)
        {
            this->a = a;
            this->b = b;
        }
        int getA()
        {
            return this->a;
        }
        int getB()
        {
            return this->b;
        }
        void print()
        {
            cout << a << " + " << b << "i" << endl;
        }
    };
    /* 两个复数相加的函数 */
    void add(Complex& c1, Complex& c2)
    {
        Complex tmp(c1.getA() + c2.getA(), c1.getB() + c2.getB());
        
        tmp.print();
    }
    /* 定义operator+函数 */
    Complex& operator+(Complex& c1, Complex& c2)
    {
        Complex tmp(c1.a + c2.a, c1.b + c2.b);
        
        return tmp;
    }
    
    int main()
    {
        Complex c1(1, 2);
        Complex c2(3, 4);
        /* 普通全局函数的两个复数相加 */
        add(c1, c2);
        /* operator+友元函数的两个复数相加 */
        Complex c3 = operator+(c1, c2);
        c3.print();
        /* 这时,我们替换operator+函数名称为+号,此时就是操作符的重载 */
        Complex c4 = c1 + c2;
        c4.print();
    
        return 0;
    }

    4.运算符重载的推演总结

    • 所谓的操作符重载,其本质还是函数,只是函数的名称换成了我们常见的操作符而已
    • 由于我们的类常常将类的属性设为私有,所以此时的操作符重载函数是友元函数,就可以快捷访问私有属性。 

     二,操作符重载编程基础

     1.操作符重载的两种方法

    • 操作符重载的本质函数为成员函数或者友元函数。
    • 关键区别在于成员函数有this指针,友元函数没有this指针。
    • 不管是友元函数重载还是成员函数重载,运算符的使用方法相同。但传递参数的方式不同,实现代码不同,应用的场合也不同。

    2.二元运算符的重载

    • 所谓的二元运算符是指操作符对两个对象进行操作。例如常见的加法就是二元操作符,对两个数进行相加。
    • 二元运算符本质函数为成员函数,则成员函数参数只有一个,为操作符右边的数据,操作符左边的数据就是this指针对象。
    • 二元运算符本质函数为友元函数,则操作符的左右两边数据都由友元函数的参数来进行传递接收。

    3.二元运算符两种重载方式的实现

    # include<iostream>
    
    using namespace std;
    
    /* 定义复数类 */
    class Complex
    {
    private:
        int a;
        int b;
    public:
        /* 友元函数方式实现操作符(+)重载 */
        friend Complex& operator+(Complex& c1, Complex c2);
    public:
        Complex(int a, int b)
        {
            this->a = a;
            this->b = b;
        }
        /* 成员函数方式实现操作符(-)重载 */
        Complex& operator-(Complex& c)
        {
            Complex tmp(this->a - c.a, this->b - c.b);
            return tmp;
        }
        void print()
        {
            cout << a << " + " << b + "i" << endl;
        }
    };
    /* 友元函数实现操作符重载的函数实现 */
    Complex& operator+(Complex& c1, Complex c2)
    {
        Complex tmp(c1.a + c2.a, c1.b + c2.b);
        return tmp;
    }
    
    int main()
    {
        /* 定义两个复数 */
        Complex c1(1, 2), c2(3, 4);
        /* 测试操作符+,用友元函数实现 */
        Complex c3 = c2 - c1;
        c3.print();
        /* 测试操作符-,用成员函数实现 */
        Complex c4 = c1 + c2;
        c4.print();
    
        return 0;
    }

    4.一元操作符的重载

    • 所谓的一元操作符就是操作只有一个要操作的数据,例如常见的自加加和自减减。
    • 一元操作符分为前置方式和后置方式,例如a++和++a。C++通过一个占位参数来区分前置运算和后置运算。
    • 前置方式我们按照正常思路书写即可,分为成员函数和友元函数两个方式实现。
    • 后置方式我们需要进行操作符重载函数的重载,我们需要用占位符来实现重载。

    5.一元操作符重载的代码实现

    # include<iostream>
    using namespace std;
    
    class Complex
    {
    private:
        int a;
        int b;
    public:
        /* 友元函数实现前置++运算符的重载 */
        friend Complex& operator++(Complex& c);
        /* 友元函数实现后置++运算符的重载 */
        friend Complex& operator++(Complex& c, int);
    public:
        Complex(int a, int b)
        {
            this->a = a;
            this->b = b;
        }
        /* 成员函数实现前置--运算符的重载 */
        Complex& operator--()
        {
            --this->a;
            --this->b;
            return *this;
        }
        /* 成员函数实现后置--运算符的重载 */
        Complex& operator--(int)
        {
            /* 返回临时的this对象后,再进行this属性的减一运算 */
            Complex tmp(this->a, this->b);
            --this->a;
            --this->b;
            return tmp;
        }
        void print()
        {
            cout << a << " + " << b << "i" << endl;
        }
    };
    /* 友元函数实现前置++运算符的重载 */
    Complex& operator++(Complex& c)
    {
        ++c.a;
        ++c.b;
        return c;
    }
    /* 友元函数实现后置++运算符的重载 */
    Complex& operator++(Complex& c,int)
    {
        Complex tmp(c.a, c.b);
        ++c.a;
        ++c.b;
        return tmp;
    }
    
    int main()
    {
        /* 定义复数 */
        Complex c1(1, 2);
        /* 前置++ */
        ++c1;
        c1.print();
        /* 前置-- */
        --c1;
        c1.print();
        /* 后置++ */
        Complex c2 = c1++;
        c2.print();
        c1.print();
        /* 后置-- */
        Complex c3 = c1--;
        c3.print();
        c1.print();
    
        return 0;
    }

    6.运算符重载的实现步骤

    • 首先必须承认操作符重载本质是一个函数,根据重载哪个操作符,书写哪个函数名称,例如:operator+()
    • 第二需要确认函数的参数,也就是确认操作符是操作几个数据,如复数自减减,则是一个数据。然后再确定是用友元函数还是成员函数实现。
    • 第三需要确认函数的返回值,也就是确认操作符运算后的结果是什么数据类型。

    7.友元函数的使用场景

    • 当要重载的操作符左边是无法修改的类(例如:ostream)则必须使用友元函数,而无法使用成员函数(因为成员函数的左侧只能是this,即类的本身)。
    • =,[],(),和->操作符只能通过成员函数进行重载。
    • 友元函数重载运算符通常用于操作符两侧类型不一致的情况。

    8.友元函数实现<<和>>操作符的重载

    # include<iostream>
    using namespace std;
    
    class Complex
    {
    private:
        int a;
        int b;
    public:
        /* 友元函数实现<<和>>操作符的重载 */
        friend ostream& operator<<(ostream& out, Complex& c);
        friend istream& operator>>(istream& in,  Complex& c);
    };
    /* 友元函数实现<<和>>操作符的重载 */
    ostream& operator<<(ostream& out, Complex& c)
    {
        out << c.a << " + " << c.b << "i";
        /* 返回输出流对象,让其支持链式编程 */
        return out;
    }
    istream& operator>>(istream& in, Complex& c)
    {
        in >> c.a >> c.b;
        return in;
    }
    
    int main()
    {
        /* 请输入一个复数 */
        cout << "请输入一个复数(实部和虚部用空格分开):" << endl;
        /* 定义一个复数 */
        Complex c;
        /* 接收输入的复数 */
        cin >> c;
        /* 打印接收的复数 */
        cout << c << endl;
    
        return 0;
    }

     三,常见操作符的重载

    1.重载赋值运算符=

    # define _CRT_SECURE_NO_WARNINGS
    # include<iostream>
    
    using namespace std;
    
    class Name
    {
    private:
        char * name;
    public:
        /* 无参构造函数 */
        Name()
        {
            this->name = NULL;
            cout << "无参构造函数执行..." << endl;
        }
        /* 有参构造函数 */
        Name(char * name)
        {
            this->name = new char[strlen(name) + 1];
            strcpy(this->name, name);
            cout << "有参构造函数执行..." << endl;
        }
        /* 拷贝构造函数 */
        Name(const Name& n)
        {
            this->name = new char[strlen(n.name) + 1];
            strcpy(this->name, n.name);
            cout << "拷贝构造函数执行..." << endl;
        }
        /* 析构函数 */
        ~Name()
        {
            if (this->name != NULL)
            {
                delete[] this->name;
                this->name = NULL;
            }
            cout << "析构函数执行..." << endl;
        }
    public:
        /* 等号操作符重载 */
        Name& operator=(Name& n)
        {
            cout << "等号操作符重载执行..." << endl;
            if (this->name != NULL)
            {
                delete[] this->name;
                this->name = NULL;
            }
            this->name = new char[strlen(n.name) + 1];
            strcpy(this->name, n.name);
            return *this;
        }
    };
    
    int main()
    {
        Name n1("王刚");
        /* 拷贝构造执行 */
        Name n2 = n1;
        /* 赋值运算符 */
        Name n3;
        n3 = n2;
    
        return 0;
    }

    2.重载数组下标运算符[]

    # include<iostream>
    
    using namespace std;
    
    class Vector
    {
    private:
        int * ptr;
        int len;
    public:
        Vector(int len)
        {
            ptr = new int[len];
            this->len = len;
        }
        ~Vector()
        {
            if (this->ptr != NULL)
            {
                delete[] this->ptr;
                this->ptr = NULL;
            }
        }
    public:
        /* 重载下标运算符 */
        int& operator[](int& i)
        {
            return this->ptr[i];
        }
    };
    
    int main()
    {
        Vector v(10);
        /* 赋值 */
        for (int i = 0; i < 10; i++)
        {
            v[i] = i;
        }
        /* 获取元素 */
        for (int i = 0; i < 10; i++)
        {
            cout << v[i] << " ";
        }
    
        return 0;
    }

    3.重载函数调用符()

    # include<iostream>
    using namespace std;
    
    class String
    {
    private:
        char * ptr;
    public:
        /* 有参构造函数 */
        String(char * ptr)
        {
            this->ptr = new char[strlen(ptr) + 1];
        }
        /* 析构函数 */
        ~String()
        {
            if (this->ptr != NULL)
            {
                delete[] this->ptr;
                this->ptr = NULL;
            }
        }
    public:
        /* 重载函数调用符() */
        String& operator()(char * ptr)
        {
            if (this->ptr != NULL)
            {
                delete[] this->ptr;
                this->ptr = NULL;
            }
            this->ptr = new char[strlen(ptr) + 1];
            strcpy(this->ptr, ptr);
            return *this;
        }
        /* 重载左移运算符 */
        friend ostream& operator<<(ostream& out, String& s);
    };
    /* 重载左移运算符 */
    ostream& operator<<(ostream& out, String& s)
    {
        out << s.ptr;
        return out;
    }
    
    int main()
    {
        /* 调用有参构造函数 */
        String str("王刚");
        /* 调用重载操作符(),将王刚修改为张文婧 */
        str("张文婧");
        /* 打印str */
        cout << str << endl;
    }
  • 相关阅读:
    认识EXTJS
    Ext面向对象开发实践(turn)
    20多个在线操作系统(webOS)一览
    一个成功的博客必须知道的80个博客工具
    163.com免费邮箱背后的传奇故事
    Android ListView的滚动条始终显示并且滚动条样式自定义
    eclipse不格式化注释
    Android横屏竖屏切换
    喝茶的好处
    Android设置Gridview中的内容不滚动,然后控件中的内容随便添加的效果。
  • 原文地址:https://www.cnblogs.com/metalsteel/p/6275597.html
Copyright © 2020-2023  润新知