zoukankan      html  css  js  c++  java
  • C++运算符重载

    可重置和不可重载的运算符

    • 运算符重载的本质:是一种特殊的函数重载,函数名称由关键字"operator"和后面的运算符组成
       
    • 可重载的运算符
      wps493F.tmp.jpeg
    • 不可重载的运算符
      wps4950.tmp.jpeg
    • 必须重载为成员函数的运算符
      wps4951.tmp.jpeg
    • 不应该被重载的运算符
      逻辑与(&&)逻辑或(||)的运算,据说会丢失短路属性; ","和"&"不要重载,因为C++对这两个运算符的作用有明确 规定,一个是逗号运算符,一个是取地址

    重载示例

    下面写一个CMyString类,并重载各种运算符,这里先给出一些比较基础的成员函数:

      class CMyString
      {
        TCHAR * m_pBuff;
        int     m_nBuffSize;
        int     m_nUsedSize;
      public:
        CMyString();
        CMyString(TCHAR * pszStr);
        int GetCountOfCharInBuff()const;
        const TCHAR* GetBuffPointer() const;
        CMyString(const CMyString & SrcObj);
        ~CMyString();
      private:
        bool CoverBuffContent(const TCHAR* pszString, int nSizeFactor);
      };
    

    源文件中实现如下:

    #include "stdafx.h"
    #include "MyString.h"
    #include <tchar.h>
    
    CMyString::CMyString():
    m_pBuff(nullptr),
    m_nUsedSize(0),
    m_nBuffSize(0)
    {
    }
    
    
    CMyString::CMyString(TCHAR * pszStr):
    m_pBuff(nullptr),
    m_nUsedSize(0),
    m_nBuffSize(0)
    {
      if (pszStr == nullptr)
      {
        return;
      }
    
      CoverBuffContent(pszStr, 2);
    }
    
    
    CMyString::CMyString(const CMyString & SrcObj):
    m_pBuff(nullptr),
    m_nUsedSize(0),
    m_nBuffSize(0)
    {
      int nBytesOfStr = SrcObj.GetCountOfCharInBuff()*sizeof(TCHAR);
      if (0 == nBytesOfStr)
      {
        return;
      }
    
      CoverBuffContent(SrcObj.GetBuffPointer(), 2);
    }
    
    
    const TCHAR* CMyString::GetBuffPointer() const
    {
      return m_pBuff;
    }
    
    
    CMyString::~CMyString()
    {
      if (m_pBuff != nullptr)
      {
        delete[] m_pBuff;
        m_pBuff = nullptr;
        m_nBuffSize = 0;
        m_nUsedSize = 0;
      }
    }
    
    int CMyString::GetCountOfCharInBuff() const
    {
      return m_nUsedSize / sizeof(TCHAR);
    }
    
    //************************************************************************
    // 函数名称: CMyString::CoverBuffContent
    // 访问权限: private 
    // 函数功能: 将pszString复制到m_pBuff中,并重置m_nUsedSize和m_nBuffSize
    // 返回值:   bool:成功返回true
    // 参数:     TCHAR * pszString:待复制的字符串
    // 参数:     int nSizeFactor:m_pBuff的尺寸放大因子
    // 注意:     
    //************************************************************************
    bool CMyString::CoverBuffContent(const TCHAR* pszString, int nSizeFactor)
    {
      int nCountOfBytes = _tcsclen(pszString) * sizeof(TCHAR);
      nSizeFactor = (nSizeFactor == 0) ? 1 : nSizeFactor;
    
      if (nCountOfBytes > m_nBuffSize)
      {
        /*如果pszString内容长度大于当前m_pBuff的长度则,则重新分配内存*/
        if (m_pBuff != nullptr)
        {
          delete[] m_pBuff;
        }
    
        m_nBuffSize = 0;
        m_nUsedSize = 0;
    
        m_nBuffSize = nCountOfBytes * nSizeFactor;
        m_pBuff = new TCHAR[m_nBuffSize];
        if (m_pBuff == nullptr)
        {
          m_nBuffSize = 0;
          return false;
        }
      }
    
      memset(m_pBuff, 0, m_nBuffSize);
      memcpy(m_pBuff, pszString, nCountOfBytes);
      m_nUsedSize = nCountOfBytes;
      return true;
    }
    
    
    //************************************************************************
    // 函数名称: CMyString::AppendToBuff
    // 访问权限: private 
    // 函数功能: 追加内容到m_pBuff尾部
    // 返回值:   bool;成功返回true
    // 参数:     const TCHAR * pszString;要追加的内容
    // 参数:     int nSizeFactor:m_pBuff的尺寸放大因子
    // 注意:     
    //************************************************************************
    bool CMyString::AppendToBuff(const TCHAR* pszString, int nSizeFactor)
    {
      int nCountOfBytes = _tcsclen(pszString) * sizeof(TCHAR);
      nSizeFactor = (nSizeFactor == 0) ? 1 : nSizeFactor;
      
      /*判断buff的剩余大小是否够用,不够用则暂存原有内容,然后重新分配内存,
        在将原有内容复制过来,在将pszString内容追加到尾部
      */
      if (nCountOfBytes > m_nBuffSize - m_nUsedSize)
      {
        int nNewBuffSize = nCountOfBytes + m_nUsedSize;
        nNewBuffSize *= nSizeFactor;
        TCHAR* pNewBuff = new TCHAR[nNewBuffSize];
        if (pNewBuff == nullptr)
        {
          return false;
        }
    
        memset(pNewBuff, 0, nNewBuffSize);
        memcpy(pNewBuff, m_pBuff, m_nUsedSize);
        m_nBuffSize = nNewBuffSize;
        delete[] m_pBuff;
        m_pBuff = pNewBuff;
      }
    
      memcpy(m_pBuff+m_nUsedSize/sizeof(TCHAR), pszString, nCountOfBytes);
      m_nUsedSize += nCountOfBytes;
      return true;
    }
    
    • 重载输入输出运算符

      • 输入运算符的第一个参数必须是istream流的非常量引用,输出运算符的第一个参数必须是ostream流的非常量引用, 因为输入输出会向流内读写内容会改变流的状态,所以该参数不能是常量,通过观察这两个流的源码发现:

        20190725082050.png
        这个两个流都禁用了拷贝构造和赋值运算符,所以流对象无法复制和赋值,所以该参数只能使用引用

      • 输出输出运算符的返回值必须得是形参中流对象的引用
        这个是为了实现在一个流对象上进行多个对象的连续输入或者输出

      • 输入输出运算符一般要重载为类的非成员函数
        例如:标准库中的string类的输入输出运算符就被重载为string的非成员函数,所以一般输出的时候都是这样写:

             std::string str = "xxxx";
             std::cout << str;
        

        如果将输入输出重载为string的成员函数那么代码得这么写:

               std::string str = "xxxx";
               string << std::cout;
        

        是不是感觉到有点别扭

      • 输入输出运算符通常要操作类的非公有数据成员,并且输入输出运算符又不能是类的成员函数,所以得是类的友元函数

        为了同时支持宽字符和窄字符,在头文件中加入下列宏定义:

        #if defined UNICODE
        #define IN_STREAM std::wistream
        #define OUT_STREAM std::wostream
        #else
        #define IN_STREAM std::istream
        #define OUT_STREAM std::ostream
        #endif
        

        将输入输出运算符声明为全局函数:

        IN_STREAM & operator >> (IN_STREAM & in, CMyString & obj);
        OUT_STREAM & operator << (OUT_STREAM & out, CMyString & obj);
        

        并在CMyString类中将这两个运算符声明为友元:
        20190725105338.png

        并在源文件中实现:

        IN_STREAM& operator >> (IN_STREAM & in, CMyString & obj)
        {
          TCHAR chBuff[4096] = { 0 };
          memset(chBuff, 0, sizeof(chBuff));
          in.getline((TCHAR*)chBuff, 4096); 
          int nInputCount = in.gcount();
          if (nInputCount > 1)
          {
            obj.AppendToBuff(chBuff, 2);
          }
          return in;
        }
        
        OUT_STREAM & operator<<(OUT_STREAM & out, CMyString & obj)
        {
          out << obj.m_pBuff;
          return out;
        }
        

         
        测试代码如下:

          CMyString str;
          CMyString str1;
          std::wcin >> str1 >> str;
          std::wcout << str1 << "
        " << str << std::endl;
        

        测试结果:
        20190725143501.png

    • 重载"+"运算符
      加号运算符要重载两个版本,一个是将其重载为成员函数,另一个将其重载为非成员函数,如果只重载了成员函数的版本,那么
      调用时运算符左侧对象必须是类对象
      对于CMyString类来说,这里重载+运算符实现两个字符串的拼接:

      CMyString operator+(const TCHAR* pszStr, const CMyString & obj)
      {
        CMyString tmp(const_cast<TCHAR*>(pszStr));
        tmp.AppendToBuff(obj.GetBuffPointer(),2);
        return tmp;
      }
      
      CMyString CMyString::operator+(const CMyString & obj)
      {
        CMyString tmp = *this;
        tmp.AppendToBuff(obj.GetBuffPointer(), 2);
        return tmp;
      }
      
      
      CMyString CMyString::operator+(const TCHAR * pszStr)
      {
        CMyString tmp = *this;
        tmp.AppendToBuff(pszStr, 2);
        return tmp;
      }
      

      测试结果:
      20190725163033.png

    • 重载赋值运算符
      赋值后可能直接会调用其它函数,所以重载后的赋值运算符要返回调用对象的引用,不然调用对象为返回的临时对象
      CMyString类的赋值运算符实现:

      CMyString& CMyString::operator=(const CMyString & obj)
      {
        CoverBuffContent(obj.GetBuffPointer(), 2);
        return *this;
      }
      
    • 重载下标运算符
      下标运算符必须得重载为成员函数,并且需要重载两个版本,一个为常量成员函数返回常量引用,供常量类对象调用, 另一个为普通成员函数,返回引用;

       TCHAR& CMyString::operator[](int nIndex)
       {
         return m_pBuff[nIndex];
       }
      
       const TCHAR& CMyString::operator[](int nIndex) const
       {
         return m_pBuff[nIndex];
       }
      

    其它运算符就不在一一实现

  • 相关阅读:
    NOI2005瑰丽华尔兹
    BZOJ4919[Lydsy1706月赛]大根堆
    BZOJ1097[POI2007]ATR-Tourist Attractions
    Luogu2973 [USACO10HOL]Driving Out the Piggies G
    Luogu5505 JSOI2011分特产
    Luogu1450 HAOI2008硬币购物
    NOI2001 炮兵阵地
    汕头市队赛 SRM 09 A 撕书
    洛谷P1196 银河英雄传说
    洛谷P3144 [USACO16OPEN]关闭农场Closing the Farm
  • 原文地址:https://www.cnblogs.com/UnknowCodeMaker/p/11245269.html
Copyright © 2011-2022 走看看