C++ 运算符重载(课堂笔记)


前言

  C++ 预定义了一组运算符 ,用来表示 对数据的运算
+ - 、*、 / % << >> & | ~ ^ && || 、!、 == != =……
只能用于基本的数据类型 整型、实型、字符型、 逻辑型 ……
cin cout 使用运算符 “ >>” 、 “ <<” 进行流操作时,要求操作数是 基本数据类型
C++ 提供了 数据抽象的手段 ,允许用户定义抽象数据类型:
 通过 调用类的成员函数 ,对它的对象进行操作。
          但是,在有些时候, 用类的成员函数 来操作对象时, 很不方便 。例如:
 对一个群体,按照他们的 体重指数 进行排序:涉 及不同对象中的“体重指数”成员属性。
 在数学上,两个复数可以直接进行 + 等运算。

 但在C++中,直接将+-用于复数是不允许的。

因此 我们希望: 对一些抽象数据类型 ,也能够 直接使用 C++ 提供的运算符
             程序更简洁

            代码更容易理解

例如:

 bool compareQuata = Bill < Jimmy
 /*Bill和Jimmy是CMan的两个对象
 比较他们的体重指数*/
 complex_a + complex_b
 /*complex_a和complex_b是两个复数对象
 求两个复数的和*/

提示:以下是本篇文章正文内容,下面案例可供参考

一、运算符重载的概念

对已有的运算符 (C++ 中预定义的运算符 ) 赋予多重的含义 ,使同一运算符 作用于 不同类型的数据 导致不同类型的行为
目的是 扩展 C++ 中提供的运算符的适用范 围 ,以用于 所表示的抽象数据类型。同一个运算符,对不同类型的操作数,所发生的行为不同。
举例:
对于 整数加法 来说,有:
int  x , y	
y = x + y ; 

对于复数加法来说,有:

complex  c1 , c2 ;  	    // 复数类对象
c1 = c1.Cadd (c2 ) ; // 调用函数计算两个复数的和

对于矩阵加法来说,有:

matrix  m1 , m2 ;	       // 矩阵类对象	
m1 = m1.Madd ( m2 ) ;// 调用函数计算两个矩阵的和

能否表示为

c1 = c1 + c2 ;  

m1 = m1+m2;

例子:

#include<iostream>
using namespace std;
class CComplex {
 private:  double real, image;
 public:
   CComplex(double r = 0, double i = 0);
   CComplex& addComplexToItself(const CComplex &r_c);
    void print() const;
};

int main(){
    CComplex a(3, 4), b(5, 6);
    a = a.addComplexToItself(b);
    //a += b; // error, 运算符’+=’没有被重载
    a.print();
}

/
#include<iostream>
using namespace std;
class CComplex {
 private:  double real, image;
 public:
   CComplex(double r = 0, double i = 0):real(r),image(i){cout<<"constructor"<<endl;}
   CComplex& addComplexToItself(const CComplex &r_c)
      {  real += r_c.real;  image += r_c.image;  return *this; }
  void print() const{
       if(real){
          cout<<real;
          if(image>0)
            cout<<"+";
       }
       if(image){
          if(abs(image)!=1)
            cout<<image;
          if(image==-1)
            cout<<"-";
          cout<<"i";
       }
       if(real==0 && image==0)
          cout<<0;
       cout<<endl;
    }
};

int main(){
    CComplex a(3, 4), b(-3, -14);
    a = a.addComplexToItself(b);
    //a += b; // error, 运算符’+=’没有被重载
    a.print();
}

问题讨论:

CComplex定义了一个addComplexToItself()成员函数实现复数类对象的自增运算。

基本数据类型变量的自增可以用’+=运算符实现。

能否直接对一个CComple类对象进行’+=运算? a += b

运算符重载的实现:

  运算符重载 是通过 函数 实现的,运算符的重载即 函数的重载 。运算符重载函数的一般形式为:
返回类型  operator 运算符符号 ( 参数说明 );

运算符重载举例:

CComplex类定义一个运算符重载函数

CComplexoperator +=

                   (const  CComplex& r_c)

编译程序 复数类对象的运算表达式 转化为 对运算符重载成员函数的调用 运算的左操作数对象 作为成员函数 调用的目标对象 右操作数 转化为运算符 函数的实参 : 
           

例子:

#include<iostream>
using namespace std;
class CComplex {
 private:  double real, image;
 public:
   CComplex(double r = 0, double i = 0):real(r),image(i){cout<<"constructor"<<endl;}
   CComplex& operator +=(const CComplex &r_c)
      {  real += r_c.real;  image += r_c.image;  return *this; }
   void print() const{
       if(real){
          cout<<real;
          if(image>0) cout<<"+";  }
       if(image){
          if(abs(image)!=1)cout<<image;
          if(image==-1)cout<<"-";
          cout<<"i";  }
       if(real==0 && image==0)
          cout<<0;
       cout<<endl; 
   }
};

int main(){
    CComplex a(3, 4), b(-3, -14);
    a += b;
    a.print();
}

运算符重载的限制:

只能重载已经存在C++运算符

运算符重载不能改变运算符操作数个数优先级结合性

运算符的操作数 必须 至少有一个某个类的类对象 ,否则不能对运算符进行重载。
重载运算符 不可以使用缺省参数
除了 赋值运算符 = 外,重载运算符可由 派生类 继承下去。

二、运算符重载函数作为类成员函数

实现

运算符重载函数可以通过 2 种形式 实现:
 类成员函数
 友元函数
这两种方式非常相似, 关键区别 在于:
  成员函数 具有 this 指针
  友员函数 没有 this 指针                                                                                                                   

说明 :

编译程序处理成员函数时,为它设置了一个this指针

重载运算符函数 中, 默认 this 指针对应的缺省参数 就是其中之 一个参数
对于 一元运算符 函数使用的就是规定的 this 指针

    所指的参数(自身的参数)

对于 二元运算 符对应是二元运算的左操作数。
运算符重载函数定义为其操作数所属类的成员函数时, 参数的个数 比运算符的操作数个数 少一个
重载 一元运算符 时,不再显式指明参数;
重载 二元运算符 时,只需显式指明一个参数;

二元运算符以成员函数形式重载,左操作数必须为类对象,目标对象作为左操作数。

声明格式:

成员运算符重载函数在类中的声明格式为:

class  X

 {  ……

   <返回数据类型> operator <运算符> (<参数表>)

};

成员运算符重载函数在类外定义的格式为:

 <返回数据类型> X::operator <运算符> (<参数表>)

  {

              <函数体>

  }

程序:

#include<iostream>
using namespace std;

class CComplex{
private:
    double real, image;
public:
  CComplex(double a=0.0, double b=0.0)
  {   real = a;      image = b;  }
  CComplex(const CComplex &r)
  {   real = r.real;      image = r.image;  }
  void print() const;
  const CComplex& operator+= (const CComplex &r_c);
  const CComplex& operator+= (double c);//实部、虚部加c
  CComplex operator+ (const CComplex &r_c) const;
  CComplex operator+ (double c) const;
};
void CComplex::print() const{
   cout<<"real="<<real<<",image="<<image<<endl;
}
const CComplex&  CComplex::operator+= (const CComplex &r_c){
   real+=r_c.real;
   image+=r_c.image;
   return *this;
}
const CComplex& CComplex::operator+= (double c)//实部、虚部加c{
{   real+=c;
    image+=c;
    return *this;
}
CComplex CComplex::operator+ (const CComplex &r_c) const{
   double r,i;
   r=real+r_c.real;
   i=image+r_c.image;
   return CComplex(r,i);
}
CComplex CComplex::operator+ (double c) const{
   double r,i;
   r=real+c;
   i=image+c;
   return CComplex(r,i);
}
int main(){
  CComplex c1(1,2),c2(3,4),c3;
  int c=5;
  c1+=c2;
  c1.print();
  c1+=c;
  c1.print();
  c3=c1+c2;
  c3.print();
  c3=c1+c;
  c3.print();
  return 1;
}

三.读入数据

运算符重载函数可以用友元函数的形式来实现。

函数参数的个数 运算符的操作数个数 相同
第一个参数 表示 左操作数
第二个参数 表示 右操作数
参数 中必须有一个类型为 类对象或类对象引用

赋值运算符‘=、下标运算符‘[ ]、成员选择运算符‘->和函数调用运算符‘()、所有的类型转换运算符不能用友元函数形式重载

声明格式:

友元运算符重载函数在类中的声明格式为:

class  X { 

   ……

friend  <返回数据类型> operator <运算符> (<参数表>)

};

友元运算符重载函数在类外定义的格式为:

 <返回数据类型operator <运算符> (<参数表>)

 {

          <函数体>

  }

程序:

#include<iostream>
using namespace std;

class CComplex{
private:
  double real, image;
public:
  CComplex(double a=0.0, double b=0.0)
  {   real = a;      image = b;  }
  CComplex(double c) { real = c; image = 0.0; }
  void print() const;
  friend void operator+= (CComplex &r_x, const  CComplex &r_y);
  friend CComplex operator+ (const CComplex &r_x, const CComplex &r_y);
};

void CComplex::print() const{
   cout<<"real="<<real<<",image="<<image<<endl;
}
void  operator+= (CComplex &r_x, const  CComplex &r_y){
   r_x.real+=r_y.real;
   r_x.image+=r_y.image;
}
CComplex operator+ (const CComplex &r_x, const CComplex &r_y){
   double r,i;
   r=r_x.real+r_y.real;
   i=r_x.image+r_y.image;
   CComplex c(r,i);
   return c;
}
int main(){
  CComplex c1(1,2),c2(3,4),c3;
  c1+=c2;
  c1.print();
  c3=c1+c2;
  c3.print();
  return 1;
}

一元运算符重载:

如同“++运算符有前缀后缀两种使用形式一样,“++”和“--”重载运算符也有前缀后缀两种运算符重载形式,以“++”重载运算符为例,其语法格式如下:

<函数类型> operator ++();   	//前缀运算
<函数类型> operator ++(int); 	//后缀运算

 使用前缀运算符的语法格式如下:

++<对象>;

使用后缀运算符的语法格式如下:

<对象>++;

1.成员函数重载实例:

#include<iostream>
using namespace std;

class Increase{
private: 
    int value;
public:  
    Increase(int x):value(x){}
    void display(){cout <<"value =" <<value <<endl; }
    Increase & operator++();      	//前增量
    Increase operator++(int);     	//后增量
};
Increase & Increase::operator++()
{  value++;                  	//先增量
   return *this;            	//再返回原对象
}
Increase Increase::operator++(int)
{  Increase temp(*this);     //临时对象存放原有对象值
   value++;                   	//原有对象增量修改
   return temp;           	//返回原有对象值
}
int main()
{  Increase n(20);
   n.display();
   (n++).display();                  
  //显示临时对象值
    n.display();                     
  //显示原有对象
    ++n;
    n.display();
    ++(++n);
    n.display();   
}

运行结果:

value=20

value=20

value=21

value=22

        value=24

 2、友元函数重载示例:

#include<iostream>
using namespace std;

class Increase{
private:
  	int value;
public:
  	Increase(int x):value(x){}
  	friend Increase & operator++(Increase &);     	//前增量
  	friend Increase operator++(Increase &,int);    	//后增量
  	void display(){ cout <<"value=" <<value <<endl; }
};
Increase & operator++(Increase & a)
{  	a.value++;                       	//前增量
  	return a;                        	//再返回原对象
}
Increase operator++(Increase& a, int)
{   Increase temp(a);           //通过拷贝构造函数保存原有对象值
  	a.value++;                  //原有对象增量修改
  	return temp;                //返回原有对象值
}
int main()
{
  	Increase n(20);
  	n.display();
    (n++).display();                 	//显示临时对象值
  	n.display();                     	//显示原有对象
  	++n;
  	n.display();
  	++(++n);
  	n.display();
  	//(n++)++;                         	
  	n.display();
}

 编程练习题:

 编程实现一个日期类 Date ,包括年、月、日等私有数据成员。要求实现日期的基本运算,如一个日期加上天数、一个日期减去天数、两日期相差的天数等。
#include<iostream>
#include<iomanip>
using namespace std;

class Date{
   int year,month,day;
   int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
public:
   Date(int y=0,int m=0,int d=0):year(y),month(m),day(d){}
   void judge1(int y){
      if(y%400==0 || (y%4==0 && y%100!=0))
        days[2]=29;
      else
        days[2]=28;
   }
   long judge2(int y){
      if(y%400==0 || (y%4==0 && y%100!=0))
        return 366;
      else
        return 365;
   }
   Date operator+(int d){
      Date t(*this);
      d+=t.day;
      judge1(t.year);
      while(d>days[t.month]){
           d-=days[t.month];
           t.month++;
           if(t.month==13){
              t.month=1;
              t.year++;
              judge1(t.year);
           }
      }
      t.day=d;
      return t;
   }
   Date operator-(int d){
      Date t(*this);
      d=t.day-d;
      judge1(t.year);
      while(d<=0){
        t.month--;
        if(t.month==0){
            t.month=12;
            t.year--;
            judge1(t.year);
        }
        d+=days[t.month];
      }
      t.day=d;
      return t;
   }
   long operator-(const Date& date){
       int startyear=year<date.year?year:date.year;

       long sum1=day;
       for(int i=startyear;i<year;i++)
        sum1+=judge2(i);
       judge1(year);
       for(int i=1;i<month;i++)
        sum1+=days[i];

       long sum2=date.day;
       for(int i=startyear;i<date.year;i++)
        sum2+=judge2(i);
       judge1(date.year);
       for(int i=1;i<date.month;i++)
        sum2+=days[i];

       return sum1-sum2;
   }
   void print(){
      cout<<year<<"-"<<setfill('0')<<setw(2)<<month<<"-"<<setfill('0')<<setw(2)<<day<<endl;
   }
};

int main(){
  Date d1(2022,12,31),d2(2022,1,1),d3;
  d3=d1+1;
  d3.print();
  d3=d2-1;
  d3.print();
  cout<<d1-d2<<endl;
}

四、类型转换

类型转换 是将 一种类型的值 转换为 另一种类型的值
对于 类型 ,是否也存在一种类型转换机制,使得 类对象之间 能进行类型转换
C++ 语言中, 被视为 用户定义的类型 ,可以像系统预定义类型一样进行类型转换。
C++ 语言允许的类型转换:
 
C++ 语言允许的类型转换有 4
标准 类型 -> 标准 类型
标准 类型 -> 类型
类型 -> 标准 类型
类型 -> 类型

 标准类型是classstructunion类型外的其他所有类型 

对于标准类型, C++ 语言提供了 两种 类型转换
隐式 类型转换
显式 类型转换

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荔枝啵啵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值