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 << "\n" << 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]; } 
其它运算符就不在一一实现
 
                    
                     
                    
                 
                    
                







 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号