C++难点九:运算符重载

1. 加号运算符重载

1.1 成员函数

#include <iostream>
#include<string.h>
using namespace std;
//重载加号之成员函数的重载
class Point
{
public:
    int x;
    int y;
    Point():x(1),y(1)
    {
        
    }
    Point operator+(Point &p)
    {
        Point temp;
        temp.x+=p.x;
        temp.y+=p.y;
        return temp;
    }
};

int main()
{
    Point p1;
    Point p2;
    Point p3=p1+p2;
    cout<<p3.x<<" "<<p3.y<<endl;
}

注:Point p3=p1+p2;的本体是Point p3=p1.operator+(p2);为方便记忆,编译器可以帮忙自动转换。

1.2 全局函数

#include <iostream>
#include<string.h>
using namespace std;
//重载加号之成员函数的重载
class Point
{
public:
    int x;
    int y;
    Point():x(1),y(1)
    {
        
    }
   
};

Point operator+(Point &p1,Point &p2)
{
    Point temp;
    temp.x=p1.x+p2.x;
    temp.y=p1.y+p2.y;
    return temp;
}
Point operator+(Point &p1,int num)
{
    Point temp;
    temp.x=p1.x + num;
    temp.y=p1.y;
    return temp;
}
int main()
{
    Point p1;
    Point p2;
    Point p3=p1+p2;
    cout<<p3.x<<" "<<p3.y<<endl;
    Point p4=p1+ 4;
    cout<<p4.x<<" ";
}

2. 左移运算符重载

2.1 成员函数

<<一般不利用成员函数重载,因为cout<<p;一般是cout在左边p在右边,但是如果调用成员函数的话就是p.operator<<cout,编译器会简化成p<<cout;

2.2 全局函数

#include <iostream>
#include<string.h>
using namespace std;
//重载左移运算符之成员函数的重载
class Point
{
public:
    int x;
    int y;
    Point():x(1),y(1)
    {
        
    }
   
};

ostream& operator<<(ostream& cout,Point p)
{
    cout<<"p.x:"<<p.x<<" "<<"p.y:"<<p.y<<endl;
    return cout;
}
//注:要写成返回值是ostream&类型,不然下面的main函数中p1后不能再进行链式编程,如p1<<endl
int main()
{
    Point p1;
    cout<<p1<<endl;
}

注:cout<<p1;的本体是<<(cout,p1)为方便记忆,编译器可以帮忙自动转换。<<(cout,p1)返回的是一个ostream&类型的cout,而cout后面是可以加<<的也就是说,<<(cout,p1)后面又是可以直接加<<的,这也是链式编程的一种思想。

3. 递增运算符重载

目的:我们进行递增运算符重载,是为了让我们自己的数据类型MyInteger能够实现:

MyInteger myInteger;
++ myInteger;//或myInteger++;

3.1 成员函数

3.1.1 前置递增

#include <iostream>
using namespace std;

class MyInteger
{
public:
// 为了让operator能够访问integer.m_integer
    friend ostream& operator<<(ostream& cout,MyInteger integer); 
    MyInteger()
    {
        m_integer = 0;
    }
    // 前置递增 ++a
    MyInteger& operator++()
    {
        m_integer++;
        return *this;//这里的*this代表的是main或者其他函数中由MyInteger m;而创建出来的指向m这个对象的指针
    }  
    int m_integer;
};

// 为了能够 cout<<myinteger;需要先重载一下<<左移运算符
ostream& operator<<(ostream& cout,MyInteger integer)
{
    cout<<integer.m_integer;
    return cout;
}

int main()
{
    MyInteger myinteger;
    cout<<"myinteger:"<<myinteger<<endl;
    cout<<"++myinteger:"<<++myinteger<<endl;
    return 0;
}

3.1.2 后置递增

#include <iostream>
using namespace std;

class MyInteger
{
public:
// 为了让operator能够访问integer.m_integer
    friend ostream& operator<<(ostream& cout,MyInteger integer); 
    MyInteger()
    {
        m_integer = 0;
    }
    // 前置递增 ++a
    MyInteger& operator++()
    {
        m_integer++;
        return *this;//这里的*this代表的是main或者其他函数中由MyInteger m;而创建出来的指向m这个对象的指针
    }
    
    // 后置递增  a++
    MyInteger operator++(int)//这里为什么不用MyInteger返回temp的引用呢?原因很简单。返回局部变量的引用是非法的。
    {
        MyInteger temp = *this;
        m_integer++;
        return temp;
    }
    
    int m_integer;
};

// 为了能够 cout<<myinteger;需要先重载一下<<左移运算符
ostream& operator<<(ostream& cout,MyInteger integer)
{
    cout<<integer.m_integer;
    return cout;
}

int main()
{
    MyInteger myinteger;
    cout<<"myinteger:"<<myinteger<<endl;
    cout<<"++myinteger:"<<++myinteger<<endl;
    cout<<"myinteger++:"<<myinteger++<<endl;
    return 0;
}

3.2 全局函数【是没有的,我自己瞎写的】

3.2.1 前置递增

#include <iostream>
using namespace std;

class MyInteger
{
public:
// 为了让operator能够访问integer.m_integer
    friend ostream& operator<<(ostream& cout,MyInteger &integer); 
    friend MyInteger& operator++(MyInteger& integer);
    MyInteger()
    {
        m_integer = 0;
    }
  
    int m_integer;
};

// 为了能够 cout<<myinteger;需要先重载一下<<左移运算符
ostream& operator<<(ostream& cout,MyInteger &integer)
{
    cout<<integer.m_integer;
    return cout;
}

//++a
MyInteger& operator++(MyInteger& integer)//之所以返回&而不是返回值,因为一直要对一个数据进行操作,比如++(++a)
{
    integer.m_integer++;
    return integer;
}


int main()
{
    MyInteger myinteger;
    cout<<"myinteger:"<<myinteger<<endl;
    cout<<"++myinteger:"<<++myinteger<<endl;
 //   cout<<"myinteger++:"<<myinteger++<<endl;
    return 0;
}

3.2.2 后置递增

a++,似乎是实现不了,因为如果实现的话operator++()里没参数就没办法实现对前面的值++,在网上也没见到有人用全局函数做重载递增的。

4. 赋值运算符重载

与难点六(深拷贝、浅拷贝)一样,这里也会出现深浅拷贝问题,也即开辟在堆区的数据重复析构。我们可以看一下错误的来源:

#include <iostream>
#include <string.h>
using namespace std;

class Person
{
public:
    Person(string name)
    {
        m_name = new string(name);
    }
    
    ~Person()
    {
        if (m_name!=NULL)
        {
            delete m_name;
            m_name=NULL;
        }
    }
    string* m_name;
};

int main()
{
    Person p1("Tom");
    Person p2=p1;
    return 0;
}

不加这个析构函数的时候貌似风平浪静,但是实际上暗流涌动。加上析构,立马表现出与深浅拷贝析构一样的不干净。

解决问题:

#include <iostream>
#include <string.h>
using namespace std;

class Person
{
public:
    Person(string name)
    {
        m_name = new string(name);
    }
    
    Person& operator=(Person& p2)
    {
        if(m_name!=NULL)
        {
            delete m_name;
            m_name=NULL;
        }
        m_name= new string(*p2.m_name);
        return *this;
    }
    
    ~Person()
    {
        if (m_name!=NULL)
        {
            delete m_name;
            m_name=NULL;
        }
    }
    string* m_name;
};

int main()
{
    Person p1("Tom");
    Person p2("Jerry");
    p2=p1;
    cout<<*p2.m_name;
    return 0;
}

注意:这里的重载函数的参数一定要以引用或者指针的形式传入,不然在传入的时候进行了一次拷贝将赋值右边p2的值传入的时候临时变量记录的p2的属性m_Age的地址,而出了赋值运算符重载函数会进行一次析构 这时p2的属性new出来的空间已经被释放了,最后结束调用虽然你深拷贝了但是程序还是会崩
【这地方我也有点迷 学的时候是大半夜迷迷糊糊的 以后找个机会要复习一下】

5. 关系运算符重载

自定义数据类型的比较(相等与不相等)

#include <iostream>
#include <string.h>
using namespace std;

class Person
{
public:
    Person(string str,int Age):name(str),age(Age)
    {
        
    }
   bool operator==(Person &p2)
   {
       if (this->name==p2.name&&this->age==p2.age)
         return 1;
       else 
         return 0;
   }
   
   bool operator!=( Person &p2)
   {
       if (this->name!=p2.name||this->age!=p2.age)
         return 1;
       else 
         return 0;
   }
    
    string name;
    int age;
};

int main()
{
    Person p1("Tom",18);
    Person p2("Tom",19);
    if(p1==p2)
    {
        cout<<"相等"<<endl;
    }
    else 
        cout<<"不相等"<<endl;
    if(p1!=p2)
    {
        cout<<"不相等"<<endl;
    }
    else 
        cout<<"相等"<<endl;    
        
    return 0;
}

6. 函数调用运算符重载(仿函数)

6.1“仿函数”名称的来源

由于调用的格式非常像一个函数,所以又称为仿函数。

#include <iostream>
#include <string.h>
using namespace std;

class Point
{
public:
   void operator()()
   {
       cout<<"operator()的调用"<<endl;
   }
   
   void operator()(string num)
   {
        cout<<"operator(string num)的调用"<<endl;
   }
};

int main()
{
    Point point;
    point.operator()();//原本应该这么调用
    point();//编译器简化以后可以这么调用
    point.operator()("xiaoming");//原本应该这么调用重载函数
    point("xiaoming");//编译器简化后的重载函数的调用
    return 0;
}

6.2 函数的参数列表、返回值都比较灵活

例:

#include <iostream>
#include <string.h>
using namespace std;

class Point
{
public:
   void operator()()
   {
       cout<<"operator()的调用"<<endl;
   }
   
   void operator()(string num)
   {
        cout<<"operator(string num)的调用"<<endl;
   }
   
   int operator()(int a,int b)
   {
       cout<<"int operator()(int a,int b)的调用"<<endl;
       return a+b;
   }
};

int main()
{
    Point point;
    point.operator()();//原本应该这么调用
    point();//编译器简化以后可以这么调用
    point.operator()("xiaoming");//原本应该这么调用重载函数
    point("xiaoming");//编译器简化后的重载函数的调用
    
    cout<<point(3,4);
    return 0;
}

6.3 匿名对象(匿名函数对象)

如果不想创建对象,那就写一个匿名的,当前行执行完立即被释放。而因为里面又有函数重载了一个小括号,所以称之为匿名函数对象。第一个小括号,说明是在创建匿名对象;第二个小括号,说明是在使用重载的()运算符。
例:

#include <iostream>
#include <string.h>
using namespace std;

class Point
{
public:
  void operator()()
   {
       cout<<"operator()的调用"<<endl;
   }
   
   void operator()(string num)
   {
        cout<<"operator(string num)的调用"<<endl;
   }

};

int main()
{
    Point()();
    Point()("xiaoming");//编译器简化后的重载函数的调用
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值