当前位置 : 主页 > 编程语言 > c语言 >

一文搞懂C++中的运算符重载

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 引入 一.运算符重载是什么 二.运算符重载的格式 三.部分运算符重载的实现 3.1 简单 + - * 运算符重载 3.2 ++,- - 运算符 3.3 =运算符 3.4 ,运算符 四.运算符重载注意事项 五.运算符重载
目录
  • 引入
  • 一.运算符重载是什么
  • 二.运算符重载的格式
  • 三.部分运算符重载的实现
    • 3.1 简单‘ + ’ ‘ - ’ ‘ * ’运算符重载
    • 3.2 ++,- - 运算符
    • 3.3 =运算符
    • 3.4 <<,>>运算符
  • 四.运算符重载注意事项
    • 五.运算符重载的限制
      • 六.MyString的简单实现
        • MyString.h
        • MyString.cpp

      引入

      对于基本类型的常量或变量进行运算时,我们可以使用 +、-、*、/ 等运算符,但是我们不可以使用运算符来进行对象之间的运算。

      eg:对象之间的加法运算

      class A
      {
      public:
          A(int i=0,int j=0,int k=0):m_i(i),m_j(j),m_k(k){}
          int geti() //接口
          {
              return m_i;
          }
          int getj()//接口
          {
              return m_j; 
          }
          int getk()//接口
          {
              return m_k;
          }
          void Add(A &b)
          {
              int i=m_i+b.m_j;
              int j=m_j+b.m_j;
              int k=m_k+b.m_k;
              cout<<i<<" "<<j<<" "<<k<<" "<<endl;
          }
      private:
          int m_i;
          int m_j;
          int m_k;
      };
      void main()
      {
          A a(6,6,6);
          A b(7,7,7);
          a.Add(b); 
      }

      正如例子中所说:这里我们无法进行对象之间的加法,对于加法操作我们需要使用接口,然后定义add函数进行加法的操作,这样也就导致了代码十分复杂。

      为了使得为了当前程序的可读性更好,简单明了。所以我们引入运算符重载这个概念。

      利用 C++ 提供的“运算符重载”机制,赋予运算符新的功能,就能解决用+将两个复数对象相加这样的问题。

      一.运算符重载是什么

      运算符重载:就是对已有的运算符赋予多重含义,使同一运算符作用于不同类型的数据时产生不同的行为。

      运算符重载的目的是使得 C++ 中的运算符也能够用来操作对象。

      运算符重载的实质是编写以运算符作为名称的函数。

      二.运算符重载的格式

      返回值类型  operator  运算符(形参表)
      {
          ....
      }

      这里对于返回值类型 大家可能会产生疑惑:什么是返回值类型,这里对返回值类型进行说明。

      返回类型主要包括三类:

      • 值返回
      • 引用返回
      • 指针返回

      值返回与引用返回 – 基本数据类型

      • 值返回:由运算符操作的表达式只能作为右值
      • 引用返回: 由运算符所操作的表达式可作为左值
      • 指针返回:有指针的相关操作
      void main()
      {
          int i =10;
          int j =20;
          int k =0; 
          i+j=k;// error 加号的表达式只可以做右值
          //i+j有临时空间来存储表达式的值,但是没有确定的,不能把表达式的值放在i或者j空间
          //不能作为左值的原因是 没有相应的内存空间 i有自己的空间 j有自己的空间 但是i+j没有
          //右边要赋值给左边,那么左边必须要有确定的内存空间
          k = i+j;//ok
          ++i = k;//i=30
          /*
          ++i表达式的值 不管在什么时候都是i加过1之后的值,所以不用重新开辟临时空间存储表达式的值,用i的空间即可
          ++i=k;就是把k的值放在i的内存单元
          */
          i++ = j;//error
          /*
          i++的j是i没有加过的值 但是最后i还是需要+1 所以此时i和i++不是同一个内存单元 所以需要重新开辟空间存储表达式的值,不可以这样使用
          */
          (i=j)=40;//=运算符可以作为左值 即可以引用返回
      }

      这里告诉大家如何快速判断是值返回还是引用返回:

      判断是左值还是右值

      如果对左值右值区分不是很清楚,可以参考这篇博客:

      链接: c++左值,右值,将忘值

      三.部分运算符重载的实现

      3.1 简单‘ + ’ ‘ - ’ ‘ * ’运算符重载

      对于简单‘ + ’ ‘ - ’ ‘ * ’运算符重载举例如下:

      #include<stdio.h>
      #include<iostream>
      using namespace std;
      class A
      {
      public:
          A(int i=0):m_i(i){}
          A operator+(const A& t)//这里用const是为了本身值不改变
          {
              cout << "A(+)" << endl;
              return m_i + t.m_i;
          }
          A operator-(const A& t)//这里用const是为了本身值不改变
          {
              cout << "A(-)" << endl;
              return this->m_i-t.m_i;
          }
          A operator*(const A& t)//这里用const是为了本身值不改变
          {
              cout << "A(*)" << endl;
              return this->m_i*t.m_i;
          }
          void print()
          {
              cout << m_i << endl;
          }
      private:
          int m_i;
      };
      void main()
      {
          A a(10);
          A b(20);
          (a + b).print();
          (a - b).print();
          (a * b).print();
      }

      运算结果:

      3.2 ++,- - 运算符

      自增运算符++、自减运算符–都可以被重载,但是它们有前置、后置之分。

      以++为例,假设 obj 是一个 CDemo 类的对象,++obj和obj++本应该是不一样的,前者的返回值应该是 obj 被修改后的值,而后者的返回值应该是 obj 被修改前的值。如果如下重载++运算符:

      CDemo & CDemo::operator ++ ()
      {
          //...
          return * this;
      }
      

      不论obj++还是++obj,都等价于obj.operator++()无法体现出差别。

      为了解决这个问题,C++ 规定,在重载++或- -时,允许写一个增加了无用 int 类型形参的版本,编译器处理++或–前置的表达式时,调用参数个数正常的重载函数;处理后置表达式时,调用多出一个参数的重载函数。

      对于前置运算符:左值 引用返回

      对于后置运算符:右值 值返回

      举例如下:

      #include <iostream>
      using namespace std;
      class CDemo {
      private:
          int n;
      public:
          CDemo(int i=0):n(i) { }
          CDemo & operator++(); //用于前置形式
          CDemo operator++( int ); //用于后置形式
          operator int ( ) { return n; }
          friend CDemo & operator--(CDemo & );
          friend CDemo operator--(CDemo & ,int);
      };
      CDemo & CDemo::operator++()
      {//前置 ++
          n ++;
          return * this;
      }
      CDemo CDemo::operator++(int k )
      { //后置 ++
          CDemo tmp(*this); //记录修改前的对象
          n++;
          return tmp; //返回修改前的对象
      }
      CDemo & operator--(CDemo & d)
      {//前置--
          d.n--;
          return d;
      }
      CDemo operator--(CDemo & d,int)
      {//后置--
          CDemo tmp(d);
          d.n --;
          return tmp;
      }
      int main()
      {
          CDemo d(5);
          cout << (d++ ) << ","; //等价于 d.operator++(0);
          cout << d << ",";
          cout << (++d) << ","; //等价于 d.operator++();
          cout << d << endl;
          cout << (d-- ) << ","; //等价于 operator-(d,0);
          cout << d << ",";
          cout << (--d) << ","; //等价于 operator-(d);
          cout << d << endl;
          return 0;
      }

      3.3 =运算符

      同类对象之间可以通过赋值运算符=互相赋值。如果没有经过重载,=的作用就是把左边的对象的每个成员变量都变得和右边的对象相等,即执行逐个字节拷贝的工作,这种拷贝叫作“浅拷贝”。

      对于深拷贝浅拷贝可以参考这篇博客:

      链接: c++拷贝构造函数

      有的时候,两个对象相等,从实际应用的含义上来讲,指的并不应该是两个对象的每个字节都相同,而是有其他解释,这时就需要对=进行重载。

      如果没有写=重载 呢么类会提供默认的=重载

      对于=运算符举例如下:

      A& operator=(const A& b)
      {
          cout << "=" << endl;
          m_i = b.m_i;
          return *this;
      }
      

      3.4 <<,>>运算符

      在 C++ 中,对于左移运算符<<可以和 cout 一起用于输出,因此也常被称为“输出运算符”。

      实际上,对于<<来说,他本来并没有这样的功能,之所以能和 cout 一起使用,是因为被重载了。

      cout 是 ostream 类的对象。ostream 类和 cout 都是在头文件 中声明的。ostream 类将<<重载为成员函数,而且重载了多次。为了使cout<<"Star War"能够成立,ostream 类需要将<<进行如下重载:

      ostream & ostream::operator << (const char* s)
      {
          //输出s的代码
          return * this;
      }
      

      cin 是 istream 类的对象,是在头文件 中声明的。istream 类将>>重载为成员函数,因此 cin 才能和>>连用以输入数据。一般也将>>称为“流提取运算符”或者“输入运算符”

      istream & operator>>( istream & is,Complex & c)
      {
          return is;
      }
      

      四.运算符重载注意事项

      1.可以重载成成员和友元两种形式

      对象.operator运算符(第二个运算数)–成员形式

      operator运算符(按照顺序写运算数)–友元形式

      2.重载成成员形式,将第一个运算数省略(当成this)

      重载成友元形式,参数不能省略 。

      3.一般建议赋值重载为成员(如果第一个参数是本类对象,则重载魏本类的成员形式)

      []也建议重载为成员

      << >> 重载成友元,cout<<a.左操作数是cout的类对象,不可能是本类对象,只能重载为友元。

      40运算符重载不可以改变优先级,结合性,操作数个数

      五.运算符重载的限制

      1.不可以臆造新的运算符

      2.不可以改变原有运算符的优先级,语法等特点。

      //不能将求模运算符(%)重载成使用一个操作数:
      int x;
      Time shiva;
      % x;    //无效的求模运算符
      % shiva;  //无效的重载操作符
      

      3.运算符重载不可以使用太多

      4.重载运算符含义必须清楚,不能有二异性质

      5.以下运算符不可以重载

      6.下列运算符只能通过成员函数进行重载

      • =:赋值运算符
      • ():函数调用运算符
      • []:下标运算符
      • ->:通过指针访问类成员的运算符

      六.MyString的简单实现

      MyString.h

      #ifndef MYSTRING_H
      #define MYSTRING_H
      #include<iostream>
      using namespace std;
      class mystring
      {
          char * _str;
      public:
          mystring(const char*str=nullptr);
          mystring(const mystring &another);
          mystring &operator=(const mystring&another);
          mystring operator+(const mystring&another);
          char& operator[](const int& i);
          bool  operator==(const mystring&another);
          bool  operator<(const mystring &another);
          bool  operator>(const mystring &another);
          friend ostream &operator<<(ostream&out,mystring&str);
          int size();
          ~mystring();
      };

      MyString.cpp

      #include "mystring.h"
      #include<string.h>
      int mystring::size(){
          return strlen(this->_str);
      }
      mystring::mystring (const char* str){
          if(str==nullptr)
          {
              _str=new char[1];
              _str[0]='\0';
              return;
          }
          _str=new char[strlen(str)+1];
          strcpy(_str,str);
      }
      mystring::mystring(const mystring &another){
          
          int lenth=strlen(another._str);
          _str=new char[lenth+1];
          strcpy(_str,another._str);
      
      }
      mystring& mystring::operator=( const mystring&another){
          if(*this==another)return *this;
          else {
              delete[] _str;
              int lenth=strlen(another._str);
              _str=new char[lenth+1];
              strcpy(_str,another._str);
              return *this;
          }
      }
      mystring mystring:: operator+(const mystring&another){
          mystring tmp;
          delete[] tmp._str;
          int lenth=strlen(_str)+strlen(another._str);
          tmp._str=new char[lenth+1];
          memset(tmp._str,0,lenth);
          strcat(tmp._str,_str);
          strcat(tmp._str,another._str);
          return tmp;
      }
      char& mystring:: operator[](const int& i){
          return _str[i];
      }
      bool mystring:: operator==(const mystring&another){
          if( strcmp(_str,another._str)==0)
              return true;
          else return false;
      }
      bool  mystring:: operator<(const mystring &another){
          if( strcmp(_str,another._str)<0)
              return true;
          else return false;
      }
      bool  mystring:: operator>(const mystring &another){
          if( strcmp(_str,another._str)>0)
              return true;
          else return false;
      }
      
      ostream &  operator<<(ostream&out,mystring&str){
              for(int i=0;i<strlen(str._str);++i)
                  out<<str._str[i];
              return out;
      }
      
      mystring:: ~mystring(){
          delete[]_str;
      }

      测试函数:

      #include<iostream>
      #include<mystring.h>
      #include<string>
      using namespace std;
      int main(){
       mystring test1("hello");
       cout<<test1<<endl;
       cout<<test1[0]<<endl;
       mystring test2("world");
       cout<<test2<<endl;
        mystring test3=test1+test2;
        cout<<test3<<endl;
        if(test1>test2)
            cout<<test1<<" > "<<test2<<endl;
        else if(test1==test2) cout<<test1<<" = "<<test2<<endl;
        else cout<<test1<<" < "<<test2<<endl;
        return 1;
      }

      结果:

      以上就是一文搞懂C++中的运算符重载的详细内容,更多关于C++运算符重载的资料请关注自由互联其它相关文章!

      上一篇:C语言函数之memcpy函数用法实例
      下一篇:没有了
      网友评论