zoukankan      html  css  js  c++  java
  • C++操作符重载!

    操作符重载为操作符提供不同的语义

    #include <iostream>
    
    using namespace std;
    
    struct Complex
    {
        int a;
        int b;
    };
    int main()
    {
        Complex c1 = {1,2};
        Complex c2 = {3,4};
        Complex c3 = c1 + c2;//编译出错
    
        cout << "Press any key to continue..." << endl;
        cin.get();
        return 0;
    }
    View Code

    上个例子中,不能用“+”直接操作两个结构体,改动一下,提供一个函数。

    //增加一个add函数
    #include <iostream>
    
    using namespace std;
    
    struct Complex
    {
        int a;
        int b;
    };
    Complex add(const Complex& c1,const Complex& c2)
    {
        Complex ret;
        ret.a = c1.a + c2.a;
        ret.b = c1.b + c2.b;
        return ret;
    }
    int main()
    {
        Complex c1 = {1,2};
        Complex c2 = {3,4};
        Complex c3 = add(c1,c2);//编译出错
        cout<<"c3.a = "<<c3.a<<endl;
        cout<<"c3.b = "<<c3.b<<endl;
    
        cout << "Press any key to continue..." << endl;
        cin.get();
        return 0;
    }
    View Code

    C++中操作符重载的本质

    C++中通过operator关键字可以利用函数拓展操作符,operator本质是通过函数重载实现操作符重载。

    //把add替换为“operator+"
    #include <iostream>
    
    using namespace std;
    
    struct Complex
    {
        int a;
        int b;
    };
    Complex operator+ (const Complex& c1,const Complex& c2)
    {
        Complex ret;
        ret.a = c1.a + c2.a;
        ret.b = c1.b + c2.b;
        return ret;
    }
    
    int main()
    {
        Complex c1 = {1,2};
        Complex c2 = {3,4};
        Complex c3 = operator+ (c1,c2);
        cout<<"c3.a = "<<c3.a<<endl;
        cout<<"c3.b = "<<c3.b<<endl;
        c3 = c1 + c2;
        cout<<"c3.a = "<<c3.a<<endl;
        cout<<"c3.b = "<<c3.b<<endl;
        cout << "Press any key to continue..." << endl;
        cin.get();
        return 0;
    }
    View Code

    operator关键字拓展的操作符应用到类。

    利用友元friend关键字可以例外的开放private声明的类成员的使用权限

    //友元friend和全局函数 使操作符重载应用与类
    #include <iostream>
    
    using namespace std;
    
    class Complex
    {
        int a;
        int b;
    public:
        Complex(int a=0,int b=0)
        {
            this->a = a;
            this->b = b;
        }
        int getA()
        {
            return a;
        }
        int getB()
        {
            return b;
        }
        friend Complex operator+ (const Complex& c1,const Complex& c2);
    };
    Complex operator+ (const Complex& c1,const Complex& c2)
    {
        Complex ret;
        ret.a = c1.a + c2.a;
        ret.b = c1.b + c2.b;
        return ret;
    }
    
    int main()
    {
        Complex c1(1,2);
        Complex c2(3,4);
        Complex c3 = c1 + c2;
        cout<<"c3.a = "<<c3.getA()<<endl;
        cout<<"c3.b = "<<c3.getB()<<endl;
        cout << "Press any key to continue..." << endl;
        cin.get();
        return 0;
    }
    View Code

    以上是“+”操作符,接下来重载“<<”操作符

    //左移操作符重载
    #include <iostream>
    
    using namespace std;
    
    class Complex
    {
        int a;
        int b;
    public:
        Complex(int a=0,int b=0)
        {
            this->a = a;
            this->b = b;
        }
        int getA()
        {
            return a;
        }
        int getB()
        {
            return b;
        }
        friend Complex operator+ (const Complex& c1,const Complex& c2);
        friend ostream& operator<< (ostream& out,const Complex& c);
    };
    Complex operator+ (const Complex& c1,const Complex& c2)
    {
        Complex ret;
        ret.a = c1.a + c2.a;
        ret.b = c1.b + c2.b;
        return ret;
    }
    ostream& operator<< (ostream& out,const Complex& c)
    {
        out<<c.a<<"+"<<c.b<<"i";
        return out;//返回ostream类型的out 是为了能连续输出
    }
    int main()
    {
        Complex c1(1,2);
        Complex c2(3,4);
        Complex c3 = c1 + c2;
        //cout<<c1; -> operator<<(cout,c1) 如果没有返回cout的话,不能接着输出endl
        cout<<c1<<endl;//->((operator<<(cout,c1)))<<endl;
        cout<<c2<<endl;
        cout<<c3<<endl;
        cout << "Press any key to continue..." << endl;
        cin.get();
        return 0;
    }
    View Code

    小结:

    1、操作符重载的本质是通过函数扩展操作符的语义    2、operator关键字是操作符重载的关键

    3、friend关键字可以函数或类开发访问权限               4、操作符重载遵循函数重载的规则

    通过operator关键字能够讲操作符定义为全局函数,操作符重载的本质就是函数重载,那么类的成员函数是否可以作为操作符重载的函数

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    using namespace std;
    
    class Complex
    {
        int a;
        int b;
    public:
        Complex(int a,int b)
        {
            this ->a = a;
            this ->b = b;
        }
        int getA()
        {
            return a;
        }
        int getB()
        {
            return b;
        }
        Complex operator+ (const Complex& c2);
        friend ostream& operator<< (ostream& out,const Complex& c);
    };
    Complex Complex::operator+ (const Complex& c2)
    {
        Complex ret(0,0);
        ret.a = this->a + c2.a;
        ret.b = this->b + c2.b;
        return ret;
    }
    ostream& operator<< (ostream& out,const Complex& c)
    {
        out<<c.a<<" + "<<c.b<<"i";//数学里的虚数表示法
        return out;//考虑c++标准库重载的左移操作符支持链式调用,所以要返回cout,如果不返回,则不能接着返回endl了;
    }
    int main(int argc,char *argv[])
    {
        Complex c1(1,2);
        Complex c2(3,4);
        Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)
    
        cout<<c1<<endl;
        cout<<c2<<endl;
        cout<<c3<<endl;
        cout << "Press the enter key to continue ...";
        cin.get();
        return EXIT_SUCCESS;
    }
    View Code

    输出结果一样。

    用成员函数重载的操作符比全局操作符函数少一个参数,即左操作符,而且不需要friend。

    问题来了,什么时候用全局的函数重载,什么时候有成员函数重载。

    1,当无法修改左操作数的类时,使用全局函数进行重载  2,=,[],(),->操作符只能通过成员函数进行重载。

    //Array.h
    #ifndef ARRAY
    #define ARRAY
    class Array
    {
    private:
        int mLength;
        int* mSpace;
    public:
        Array(int length);
        Array(const Array& obj);
        int length();
        ~Array();
        int& operator[] (int i);
        Array& operator= (const Array& obj);
        bool operator== (const Array& obj);
        bool operator!= (const Array& obj);
    };
    #endif // ARRAY
    //Array.c
    #include "array.h"
    
    Array::Array(int length)
    {
        if(length < 0)
        {
            length = 0;
        }
        mLength = length;
        mSpace = new int[mLength];
    }
    Array::Array(const Array &obj)
    {
        mLength = obj.mLength;
        mSpace = new int[mLength];
        for(int i = 0;i<mLength;i++)
        {
            mSpace[i] = obj.mSpace[i];
        }
    }
    int Array::length()
    {
        return mLength;
    }
    Array::~Array()
    {
        mLength = -1;
        delete[] mSpace;
    }
    int& Array::operator[] (int i)//作为左值的调用语句返回的必须是引用
    {
        return mSpace[i];
    }
    Array& Array::operator= (const Array& obj)//返回Array的引用是为了可以连续赋值
    {                                //a3 = a2 = a1;->a3 = a2.operator=(a1);
        delete[] mSpace;//先释放自己的原有的堆空间 因为接下来要申请
        mLength = obj.mLength;
        mSpace = new int[mLength];
        for(int i = 0;i<mLength;i++)
        {
            mSpace[i] = obj.mSpace[i];
        }
        return *this;
    }
    bool Array::operator== (const Array& obj)
    {
        bool ret = true;
        if(mLength==obj.mLength)
        {
            for(int i=0;i<mLength;i++)
            {
                if(mSpace[i] != obj.mSpace[i])
                {
                    return false;
                    break;
                }
            }
        }
        else
        {
            ret = false;
        }
        return ret;
    }
    bool Array::operator!= (const Array& obj)
    {
        return !(*this == obj);
    }
    //main.c
    #include <iostream>
    #include <cstdlib>
    #include "array.h"
    using namespace std;
    
    int main(int argc,char *argv[])
    {
        Array a1(10);
        Array a2(0);
        Array a3(1);
        for(int i = 0;i<a1.length();i++)
        {
            a1[i] = i+  1;
        }
    
       for(int i = 0;i < a1.length();i++)
        {
            cout<<"Element"<<i<<":"<<a1[i]<<endl;
        }
    
         a2 = a1;//-> a2.operator=(a1);
         //a3 = a2 = a1;//->a3 = a2.operator=(a1);
        for(int i=0;i<a2.length();i++)
        {
             cout<<"Element"<<i<<":"<<a2[i]<<endl;
        }
        if(a1 == a2)
        {
            cout<<"a1 == a2"<<endl;
        }
        if(a3!=a2)
        {
            cout<<"a3 != a2"<<endl;
        }
        cout << "Press the enter key to continue ...";
        cin.get();
        return 0;
    }
    View Code

    为什么要用到赋值操作符重载?

    C++编译器会为每个类提供默认的赋值操作符,但默认的赋值操作符只是简单的值复制,一旦有指针类的成员变量则就只复制指针,它们将指向同一片空间,而相应的空间就没用了,所以类中存在指针成员变量时就需要重载赋值操作符

    ++操作符的重载

    ++操作符只有一个操作数,且有前缀和后缀的区分。如何重载++操作符才能区分前置运算和后置运算呢?

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    using namespace std;
    
    class Complex
    {
        int a;
        int b;
    public:
        Complex(int a,int b)
        {
            this ->a = a;
            this ->b = b;
        }
        int getA()
        {
            return a;
        }
        int getB()
        {
            return b;
        }
        Complex operator+ (const Complex& c2);
        Complex operator ++(int);//占位参数
        Complex& operator ++();
        friend ostream& operator<< (ostream& out,const Complex& c);
    };
    Complex Complex::operator+ (const Complex& c2)
    {
        Complex ret(0,0);
        ret.a = this->a + c2.a;
        ret.b = this->b + c2.b;
        return ret;
    }
    ostream& operator<< (ostream& out,const Complex& c)
    {
        out<<c.a<<" + "<<c.b<<"i";//数学里的虚数表示法
        return out;//考虑c++标准库重载的左移操作符支持链式调用,所以要返回cout,如果不返回,则不能接着返回endl了;
    }
    Complex Complex:: operator ++(int)
    {
        Complex ret = *this;//先将当前对象做一个备份
        /*首先解释++后缀的原理
         int a=0;
         cout<<a++<<endl;则会打印0 且a=1。
         为了模拟这个过程则要先保存一个当前值的备份
        */
        a++;//然后当前对象进行+1操作
        b++;
        return ret;//将备份返回
    }
    Complex& Complex:: operator ++()//为什么要返回引用?
    {
        ++a;
        ++b;
        return *this;
    }
    int main(int argc,char *argv[])
    {
        Complex c1(1,2);
        Complex c2(3,4);
        Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)
    
        cout<<c1<<endl;
        cout<<c2<<endl;
        cout<<c3<<endl;
        cout << "Press the enter key to continue ...";
        cin.get();
        return EXIT_SUCCESS;
    }
    View Code

    为什么不用重载&&和||操作符?

    首先在语法上是没有错误的,但最好不要去重载,&&和||的特性是短路。

    //短路
    int a1 = 0;
    int a2 = 1;
    if(a1&&(a1+a2))
    {
        cout<<"Hello"<<endl;
    }
    //因为a1=0,则(a1+a2)根本不会执行。这个就是所谓的短路。
    //如果重载了&&
    class Test
    {
        int a;
    public:
        Test(int i)
        {
          this->a = i;
        }
        Test operator+ (const Test& obj) 
       {
          Test ret = 0;
           ret.a = this->a+obj.a;
           return ret;
        }
        bool operator&& (const Test& obj)
        {
            return a&&obj.a;
        }
    };
    Test t1 = 0;
    Test t2 =1;
    if(t1.operator&&(t1.operator+(t2)))
    {
        cout<<"Hello"<<endl;
    }
    //则会先执行+操作,违反了短路原则。

    &&和||是c++中非常特殊的操作符。

    &&和||内置实现了短路规则,操作符重载是靠函数重载来实现的,操作数作为函数参数传递,c++的函数参数都会被求值,无法实现短路规则。

    懒惰不会让你一下子跌到 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
  • 相关阅读:
    Spark权威指南(中文版)----第11章 Datasets(1)
    左右侧滑动窗口
    解决右侧滑动窗口溢出的问题
    y轴的文字左对齐
    解决echarts图表宽度不够字符被覆盖问题
    Helloworld.JaVa 第一次编程
    二叉排序树:BST: (Binary Sort(Search) Tree)
    赫夫曼编码码(Huffman Coding)
    赫夫曼树(Huffman Tree)
    堆排序
  • 原文地址:https://www.cnblogs.com/Rainingday/p/7574223.html
Copyright © 2011-2022 走看看