美文网首页
013-运算符重载

013-运算符重载

作者: 一亩三分甜 | 来源:发表于2021-10-04 18:33 被阅读0次

    《C++文章汇总》
    上一篇介绍了《012-对象类型的参数和返回值、友元函数、内部类和局部类》,本文介绍运算符重载。

    1.运算符重载

    ◼ 运算符重载(操作符重载):可以为运算符增加一些新的功能

    class Point {
        friend Point operator+(Point,Point);
    private:
        int m_x;
        int m_y;
    public:
        int getX(){return m_x;};
        int getY(){return m_y;};
        Point(int x,int y):m_x(x),m_y(y){}
        void display(){
            cout << "(" << m_x <<", " << m_y << ")" << endl;
        }
    };
    Point operator+(Point p1,Point p2){
        return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3 = p1+p2;
        p3.display();
        getchar();
        return 0;
    }
    //输出
    (30, 50)
    

    若三个点一起相加,则operator+方法会进入两次,p1+p2+p3 <==> operator+(operator+(p1,p2),p3)

    Point operator+(Point p1,Point p2){
        cout << "Point operator+(Point p1,Point p2)" << endl;
        return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p4 = p1+p2+p3;
        p4.display();
        getchar();
        return 0;
    }
    //输出
    Point operator+(Point p1,Point p2)
    Point operator+(Point p1,Point p2)
    (60, 90)
    

    2.运算符重载完善

    运算符重载中写成引用变量,参数前加const修饰,既能接收const修饰的对象,又能接收非const修饰的对象

    class Point {
        friend Point operator+(const Point &,const Point &);
    private:
        int m_x;
        int m_y;
    public:
        int getX(){return m_x;};
        int getY(){return m_y;};
        Point(int x,int y):m_x(x),m_y(y){}
        void display(){
            cout << "(" << m_x <<", " << m_y << ")" << endl;
        }
    };
    Point operator+(const Point &p1,const Point &p2){
        cout << "Point operator+(Point p1,Point p2)" << endl;
        return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p4 = p1+p2+p3;
        //Point p5 = operator+(operator+(p1,p2),p3);
        p4.display();
        getchar();
        return 0;
    }
    //输出
    Point operator+(Point p1,Point p2)
    Point operator+(Point p1,Point p2)
    (60, 90)
    

    拷贝构造函数为什么要这样写Point(const Point &p1)?
    假设这样写Point(Point p1)会有什么后果?
    Point p(10,20);
    Point p0 = p;会调用拷贝构造函数,进入到参数Point p1 = p;此时又会调用拷贝构造函数,会进入死循环
    const修饰的参数能接受const和非const参数
    ◼ 全局函数、成员函数都支持运算符重载

    class Point {
    private:
        int m_x;
        int m_y;
    public:
        int getX(){return m_x;};
        int getY(){return m_y;};
        Point(int x,int y):m_x(x),m_y(y){}
        void display(){
            cout << "(" << m_x <<", " << m_y << ")" << endl;
        }
        Point operator+(const Point &p){
            return Point(m_x+p.m_x, m_y+p.m_y);
        };
    };
    
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p4 = p1+p2+p3;
        p4.display();
        getchar();
        return 0;
    }
    //输出
    (60, 90)
    

    I.实现减号运算符重载

    Point operator-(const Point &p){
        return Point(m_x-p.m_x, m_y-p.m_y);
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p5 = p3 - p2;
        p5.display();
        getchar();
        return 0;
    }
    //输出
    (60, 90)
    (10, 10)
    

    会存在以下问题p1+p2 = Point(10,20),赋值没有意义,但编译器没有报错,在运算符函数重载前加const修饰符,const修饰的函数返回值无法修改,此时编译器会报错
    加const前

    图片.png
    加const后
    图片.png
    此时p4 = p1 + p2 + p3又会报错,相当于p1.operator+(p2).operator+(p3),但p1.operator+(p2)返回值是一个const修饰的对象,是无法直接调用非const修饰的成员函数的,此时需要将重载函数变为const修饰的重载函数
    图片.png
    class Point {
    private:
        int m_x;
        int m_y;
    public:
        int getX(){return m_x;};
        int getY(){return m_y;};
        Point(int x,int y):m_x(x),m_y(y){}
        void display(){
            cout << "(" << m_x <<", " << m_y << ")" << endl;
        }
        const Point operator+(const Point &p) const{
            return Point(m_x+p.m_x, m_y+p.m_y);
        };
        const Point operator-(const Point &p) const{
            return Point(m_x-p.m_x, m_y-p.m_y);
        };
    };
    
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p4 = p1+p2+p3;//相当于p1.operator+(p2).operator+(p3),但p1.operator+(p2)返回值是一个const修饰的对象,是无法直接调用非const修饰的成员函数的,此时需要将重载函数变为const修饰的重载函数
    //    p1.operator+(p2).operator+(p3);
        p4.display();
        //p1+p2 = Point(10,20);//此处赋值没有任何意义,运算符重载函数前加const修饰
        Point p5 = p3 - p2;
        p5.display();
        getchar();
        return 0;
    }
    

    II.重载运算符加减混合运算

    const Point operator+(const Point &p) const{
        return Point(m_x+p.m_x, m_y+p.m_y);
    };
    const Point operator-(const Point &p) const{
        return Point(m_x-p.m_x, m_y-p.m_y);
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        Point p3(30,40);
        Point p4 = p1+p2-p3;
        p4.display();
        getchar();
        return 0;
    }
    //输出
    (0, 10)
    

    III.加等于,使用引用&不会产生中间对象

    Point &operator+=(const Point &p){
        m_x += p.m_x;
        m_y += p.m_y;
        return *this;
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        (p1 += p2) = Point(50,60);
        p1.display();
    }
    //输出
    (50, 60)
    

    IV.等于等于,加const后常量对象也能比较

    bool operator==(const Point &p) const{
        if(m_x == p.m_x && m_y == p.m_y)
            return 1;
        else
            return 0;
    };
    int main(){
        Point p1(10,20);
        Point p2(20,30);
        cout << (p1 == p2) << endl;
    }
    //输出
    0
    

    V.不等于,加const后常量对象也能比较

    bool operator!=(const Point &p) const{
        return (m_x != p.m_x)|| (m_y != p.m_y);
    }
    

    VI.负号

    const Point operator-() const{
        return Point(-m_x,-m_y);
    }
    int main(){
        const Point p1(10,20);
        Point p2(20,30);
        Point p3 = -(-p1);
        p1.display();
        p3.display();
    }
    //输出
    (10, 20)
    (10, 20)
    

    VII.++,--

    //前置++
    Point &operator++(){
        m_x++;
        m_y++;
        return *this;
    }
    //后置++
    const Point operator++(int){
        //返回调用者之前的值
        Point old(m_x,m_y);
        m_x++;
        m_y++;
        return old;
    }
    int main(){
        Point p1(10,20);
        Point p2 = p1++ + Point(30,40);
        p1.display();
        p2.display();
    }
    //输出
    (11, 21)
    (40, 60)
    

    VIII.<<,cout相当于Java的toString方法,OC的description方法

    class Point {
        friend void operator<<(ostream &,const Point &);
        int m_x;
        int m_y;
    }
    void operator<<(ostream &cout,const Point &p){
        cout << "(" << p.m_x << "," << p.m_y << ")" << endl;
    }
    int main(){
        Point p1(10,20);
        Point p2 = p1++ + Point(30,40);
        cout << p1;
        cout << p2;
    }
    //输出
    (11,21)
    (40,60)
    

    连续打印

    class Point {
        friend ostream &operator<<(ostream &,const Point &);
    }
    ostream &operator<<(ostream &cout,const Point &p){
        cout << "(" << p.m_x << "," << p.m_y << ")";
        return cout;
    }
    int main(){
        Point p1(10,20);
        Point p2 = p1++ + Point(30,40);
        cout << p1 << p2 << 1 << 2 << 3;
    }
    //输出
    (11,21)(40,60)123
    

    系统自带的打印字符串函数要求左边cout修饰为非const,故重载打印运算符<<返回值前面不能加const,若加了const则连续打印cout << p1 << p2,cout<<p1返回const对象,const对象调用<<方法传入的接收参数为非const对象cout,会报错,所以前面的返回值类型不能加const

    //系统自带打印字符串要求左边cout修饰为非const
    void operator<<(ostream &cout,const char *string){
        
    }
    

    VIV.>>,cin从键盘接收赋值

    class Point {
        friend istream &operator>>(istream &,Point &);
    }
    istream &operator>>(istream &cin,Point &p){
        cin >> p.m_x;
        cin >> p.m_y;
        return cin;
    }
    int main(){
        Point p1(10,20);
        Point p2 = p1++ + Point(30,40);
        cin >> p1 >> p2;
        cout << p1 << p2 << endl;
        getchar();
        getchar();
        return 0;
    }
    //输出
    11 22 55 66
    (11,22)(55,66)
    

    VV.=说明,一般对象的符号如=重载后可以赋值,但cout重载后不能赋值

    class Person{
        int m_age;
        int m_height;
    public:
        Person(int age,int height):m_age(age),m_height(height){
            
        }
        Person &operator=(const Person &person){
            m_age = person.m_age;
            return *this;;
        }
        void display(){
            cout << "(" << m_age << "," << m_height << ")" << endl;
        }
    };
    
    int main(){
        Person p1(10,180);
        Person p2(15,175);
        (p1 = p2) = Person(50,20);
        p1.display();
        getchar();
        return 0;
    }
    //输出
    (50,180)
    

    禁止p1 = p2直接赋值,将重载函数私有化


    图片.png

    同理,为什么cout重载后不能赋值,因为ostream库将cout重载函数私有化了


    图片.png

    3.单例模式完善

    *rocket1 = *rocket2;//同一个对象,赋值操作没有意义,要禁止掉,将赋值操作符=私有化


    图片.png
    图片.png

    仍旧可以调用拷贝构造函数,没有意义,要禁止掉


    图片.png
    图片.png

    4.赋值运算符注意点

    调用父类的运算符重载函数

    class Person{
    public:
        int m_age;
        Person &operator=(const Person &person){
            m_age = person.m_age;
            return *this;
        }
    };
    class Student:public Person{
    public:
        int m_score;
        Student &operator=(const Student &student){
            Person::operator=(student);
            m_score = student.m_score;
            return *this;
        }
    };
    int main(){
        Student stu1;
        stu1.m_age = 10;
        stu1.m_score = 100;
        
        Student stu2;
        stu2 = stu1;
        
        getchar();
        return 0;
    }
    

    5.仿函数(函数对象)

    ◼ 仿函数:将一个对象当作一个函数一样来使用
    ◼ 对比普通函数,它作为对象可以保存状态

    int sum(int a,int b){
        return a+b;
    }
    class Sum {
        int m_age;
    public:
        int operator()(int a,int b){
            cout << "operator()(int a,int b)" << endl;
            return a+b;
        }
        void func(){
            m_age = 10;
        }
    };
    
    int main(){
        Sum sum;
        sum.func();
        cout << sum(10,20) << endl;//相当于重载运算符()
        sum(20,30);
    //    cout << sum.operator()(10,20) << endl;
        getchar();
        return 0;
    }
    //输出
    operator()(int a,int b)
    30
    operator()(int a,int b)
    

    6.运算符重载注意点

    ◼ 有些运算符不可以被重载,比如

    对象成员访问运算符:.
    域运算符:::
    三目运算符:?:
    sizeof
    ◼ 有些运算符只能重载为成员函数,比如
    赋值运算符:=
    下标运算符:[ ]
    函数运算符:( )
    指针访问成员:->

    相关文章

      网友评论

          本文标题:013-运算符重载

          本文链接:https://www.haomeiwen.com/subject/ebxwnltx.html