学习c++(5)运算符重载

一、什么是运算符重载
所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。
又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对 象cout 配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象 cin 配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同 的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<< “和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。


二、运算符重载的限制
(1)不能重载的运算符:

.
::
.*
?:
sizeof

总结:带 . 的 和 sizeof

(2)
这里写图片描述


三、重载运算符的两种方法
(1)二元运算符
这里写图片描述

例如1:
//通过类成员函数完成-操作符重载
//函数声明 Complex operator-(Complex &c2)
//函数调用分析
//用类成员函数实现-运算符重载
  Complex c4 = c1 - c2;
  c4.printCom();
  //c1.operator-(c2);

例如2:
//通过全局函数方法完成+操作符重载
//函数声明 Complex operator+(Complex &c1, Complex &c2) 
//函数调用分析
int main()
{
    Complex c1(1, 2), c2(3, 4);
    //Complex c31 = operator+(c1, c2);
    Complex c3 = c1 + c2; 
    c3.printCom();
}

(2)一元运算符
这里写图片描述

例如3
//前置++操作符 用全局函数实现 
Complex& operator++(Complex &c1) 
{
  c1.a ++;   
  c1.b ++;
  return c1;  
}
//调用方法
  ++c1 ; //=è需要写出操作符重载函数原形
  c1.printCom();

//运算符重载函数名定义
  //首先承认操作符重载是一个函数 定义函数名èoperator++
  //分析函数参数 根据左右操作数的个数,èoperator++(Complex &c1)
  //分析函数返回值è Complex& operator++(Complex &c1) 返回它自身

例如4
//4.1前置—操作符 成员函数实现
Complex& operator--()
{
  this->a--;
  this->b--;
  return *this;
}

      //4.2调用方法
           --c1;
           c1.printCom();
      //4.3前置—运算符重载函数名定义
      //c1.operator--()

例如5 
      //5.1 //后置++ 操作符 用全局函数实现
Complex operator++(Complex &c1, int) 
{
  Complex tmp = c1;
  c1.a++;
  c1.b++;
  return tmp;
}
//5.2 调用方法
c1 ++ ; //先使用 后++
//5.3 后置++运算符重载函数名定义
 Complex operator++(Complex &c1, int) //函数占位参数 和 前置++ 相区别

例如6
//6.1 后置— 操作符 用类成员函数实现
      Complex operator--(int) 
      {
           Complex tmp = *this;
           this->a--;
           this->b--;
           return tmp;
      }
//6.2 调用方法
c1 ++ ; //先使用 后++
//6.3 后置--运算符重载函数名定义
 Complex operator--(int) //函数占位参数 和 前置-- 相区别

(3)前置 和 后置 运算符总结
C++中通过一个占位参数来区分前置运算和后置运算
这里写图片描述


四、友元函数和成员函数的选择方法:

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

五、重载赋值运算符 =
结论:
(1) 先释放旧的内存
(2) 返回一个引用
(3) =操作符 从右向左

#include <iostream>
using namespace std;

class  Name
{
public:
  Name(const char *myp)
  {
    m_len = strlen(myp);
    m_p =(char *) malloc(m_len + 1); //
    strcpy(m_p, myp);
  }

  //Name obj2 = obj1;
  //解决方案: 手工的编写拷贝构造函数 使用深copy
  Name(const Name& obj1)
  {
    m_len = obj1.m_len;
    m_p = (char *)malloc(m_len + 1);
    strcpy(m_p, obj1.m_p);
  }

  //obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
  //obj3.operator=(obj1)

  Name& operator=(Name &obj1)
  {
    //先释放旧的内存
    if (this->m_p != NULL)
    {
       delete[] m_p;
       m_len = 0;
    }
    //2 根据obj1分配内存大小
    this->m_len = obj1.m_len;
    this->m_p = new char [m_len+1];

    //把obj1赋值
    strcpy(m_p, obj1.m_p);
    return *this;
  }

  ~Name()
  {
    if (m_p != NULL)
    {
       free(m_p);
       m_p = NULL;
       m_len = 0;
    }
  }
protected:
private:
  char *m_p ;
  int m_len; 
};

//对象析构的时候 出现coredump
void objplaymain()
{
  Name obj1("abcdefg");
  Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
  Name obj3("obj3");

  obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
  //obj3.operator=(obj1)
  //operato=(Name &obj1)

  obj1 = obj2 = obj3;
  //obj2.operator=(obj3);
  //obj1 = void;
}

int main()
{
  objplaymain();
  cout<<"hello..."<<endl;

  return 

六、为什么不要重载 && 和 | |
1)&&和||是C++中非常特殊的操作符
2)&&和||内置实现了短路规则
3)操作符重载是靠函数重载来完成的
4)操作数作为函数参数传递
5)C++的函数参数都会被求值,无法实现短路规则

#include <cstdlib>
#include <iostream>
 
using namespace std;
 
class Test
{
    int i;
public:
    Test(int i)
    {
        this->i = i;
    }
 
    Test operator+ (const Test& obj)
    {
        Test ret(0);
 
        cout<<"执行+号重载函数"<<endl;
        ret.i = i + obj.i;
        return ret;
    }
 
    bool operator&& (const Test& obj)
    {
        cout<<"执行&&重载函数"<<endl;
 
        return i && obj.i;
    }
};
 
// && 从左向右
int main()
{
    int a1 = 0;
    int a2 = 1;
 
    cout<<"注意:&&操作符的结合顺序是从左向右"<<endl;
 
    if( a1 && (a1 + a2) )
    {
        cout<<"有一个是假,则不在执行下一个表达式的计算"<<endl;
    }
 
    Test t1 = 0;
    Test t2 = 1;
 
    //if( t1 && (t1 + t2)  )
    //t1  && t1.operator+(t2)
    // t1.operator&&(  t1.operator+(t2) )
 
    //1 && || 重载他们 不会产生短路效果
    if(  (t1 + t2) && t1)
    {
        //t1.operator+(t2) && t1;
        //(t1.operator+(t2)).operator&&(t1);
 
        cout<<"两个函数都被执行了,而且是先执行了+"<<endl;
    }
 
    //2 && 运算符的结合性
    // 两个逻辑与运算符  在一块的时候, 采去谈 运算符的结合性
    // 从左到右    (t1 + t2) && t1 ; 运算结果 && t2)
    //if(  (t1 + t2) && t1 && t2)
    {
        //t1.operator+(t2) && t1;
        //(t1.operator+(t2)).operator&&(t1);
 
        cout<<"两个函数都被执行了,而且是先执行了+"<<endl;
    }
 
    return 0;
}
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值