C++细节笔记7(补充拓展)

本文介绍了一个名为CMyString的自定义字符串类,该类实现了包括构造函数、拷贝构造、字符串拼接、查找、比较和子串提取等功能。通过引用计数的方式优化内存管理,支持多种数据类型的转换并提供了格式化字符串的方法。此外,还展示了如何在实际场景中使用该类,如对象传参、返回值返回和匿名对象等。
摘要由CSDN通过智能技术生成

拷贝构造

  1. 当类没有实现拷贝构造的时候,编译器会提供一个默认的拷贝构造
  2. 默认拷贝构造即内存拷贝(通过memcpy拷贝也就是浅拷贝)
  3. 当类提供了拷贝构造时,则调用提供的拷贝构造

拷贝构造的时机

  • 对象传参, 比如调用void Test(ClassName buf)时形参需要传入ClassName的类对象,其实际上就是拷贝构造
  • 使用对象构造对象, 比如下面的例子
ClassName obj1; // 默认无参构造函数
ClassName obj2(obj1); // 显式调用了拷贝构造
  • 返回值返回类类型, 比如ClassName Test(); 被调用时会调用拷贝构造函数

匿名对象

  • 返回类对象时
  • 手动构造匿名对象, 比如ClassName().function(),通过ClassName()调用了无参构造函数并生成了匿名对象后调用了对象的function()方法

这里实现了一个完整的String工具类作为例子, 其使用了引用计数的方式

其主要功能如下:

  • 拼接追加字符串
  • 拷贝字符串
  • 查询字符串
  • 比较字符串
  • 正向与逆向的子串查找
  • 子串提取
  • 格式化字符串

首先是头文件:

// CMyString.h

#ifndef _CSMYSTRING_H
#define _CSMYSTRING_H

class CMyString
{
public:
	CMyString();
	explicit CMyString(const char* sz);
	explicit CMyString(char ch);
	CMyString(const CMyString& obj);
	~CMyString();

	inline size_t GetLen() const
	{
		return(m_nLen);
	}
	inline const char* GetStr() const
	{
		return(m_pBuff);
	}

	//拼接追加
	CMyString& Append(const char* sz);
	CMyString& Append(const CMyString& sz);
	CMyString& Append(char ch);
	CMyString& Append(int n);
	CMyString& Append(float f);
	CMyString& Append(double dbl);

	//查询
	int Find(const char* sz); //-1 找不到
	int Find(const CMyString& obj);
	int ReverseFind(const char* sz);
	int ReverseFind(const CMyString& obj);

	//拷贝
	CMyString& Copy(const char* sz);
	CMyString& Copy(const CMyString& obj);

	//比较
	int Compare(const char* sz);
	int Compare(const CMyString& obj);

	//字串提取
	CMyString Left(size_t nCount); //从字符串左侧提出nCount个字符
	CMyString Right(size_t nCount);
	CMyString Mid(int nIdx, size_t nCount);//从索引nIdx提出nCount个字符

	static CMyString ValueOf(bool);											
	static CMyString ValueOf(char c);										
	static CMyString ValueOf(double d);										
	static CMyString ValueOf(float f);										
	static CMyString ValueOf(int i);										
	static CMyString ValueOf(long i);										
	static CMyString ValueOf(short i);										
	static CMyString ValueOf(const char* data);		

	static CMyString CopyValueOf(const char* data, int offset, int count);	
	static CMyString StringFromFormat(const char *format, ...);				

private:
	bool Init(char* pBuff, size_t size_t_Len, size_t size_t_BufSize, size_t* pSize_t_Cnt);
	void SetStr(const char* sz);
	void ZeroMemory(CMyString *pCStr);
	void DeleteMemory();

	void ReverseString(char *pszStr);
private:
	char* m_pBuff = nullptr;	// 存储字符串的缓冲区
	size_t m_nLen;				// 字符串的长度
	size_t m_nBuffSize;			// 缓冲区的大小
	size_t *m_pSize_t_Cnt;		// 引用计数
};

#endif 

接着是cpp文件

#define _CRT_SECURE_NO_WARNINGS
#include "CMyString.h"
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>

CMyString::CMyString()
{
	ZeroMemory(this);
}

CMyString::CMyString(
    const char* sz
    )
{
	int iLen = 0;

	if (nullptr != sz)
	{
		iLen = strlen(sz) + 1;
		Init((char *)sz, iLen - 1, iLen, nullptr);
	}
	else
	{
		ZeroMemory(this);
	}
}

CMyString::CMyString(
    const CMyString& obj
    )
{
	Init(obj.m_pBuff, obj.m_nLen, obj.m_nBuffSize, obj.m_pSize_t_Cnt);
}

CMyString::CMyString(
    char ch
    )
{
	if ((ch >= 32) && (ch <= 126))
	{
		char szBuf[2] = { 0 };
		szBuf[0] = ch;

		Init(szBuf, 1, 2, nullptr);
	}
	else
	{
		ZeroMemory(this);
	}
}

CMyString::~CMyString()
{
	DeleteMemory();
}


void 
CMyString::DeleteMemory()
{
	int iCnt = 0;

	if (nullptr != m_pBuff)
	{
		--(*m_pSize_t_Cnt);
		iCnt = *m_pSize_t_Cnt;

		if (0 >= iCnt)
		{
			delete[] m_pBuff;
			delete m_pSize_t_Cnt;
			ZeroMemory(this);
		}
	}
}


void 
CMyString::ReverseString(
    char* pszStr
    )
{
	size_t uiLenOfString = 0;
	char ch;

	if (nullptr == pszStr)
	{
		return;
	}
	uiLenOfString = strlen(pszStr);
	
	for (size_t i = 0, j = uiLenOfString - 1; i < j; ++i, --j)
	{
		ch = pszStr[i];
		pszStr[i] = pszStr[j];
		pszStr[j] = ch;
	}
}

CMyString& 
CMyString::Append(
	const char* sz
	)
{
	size_t iLen = 0;
	size_t iTotalLen = 0;
	char* pNewBuf = nullptr;

	if (nullptr == sz)
	{
		return(*this);
	}
	
	iLen = strlen(sz);
	if (nullptr != m_pBuff)
	{
		// 获取加上新字符串需要的总长
		iTotalLen = iLen + m_nLen + 1;
		// 如果原堆内存空间足够容纳新增字符串, 直接strcat
		if (m_nBuffSize >= iTotalLen)
		{
			strcat(m_pBuff, sz);
		}
		// 不满足的情况, 需要重新分配内存
		else
		{
			// 分配新内存
			pNewBuf = new char[iTotalLen];
			// 分配成功
			if (nullptr != pNewBuf)
			{
				// 把新旧内容拷贝进来
				memset(pNewBuf, 0, iTotalLen);
				strcpy(pNewBuf, m_pBuff);
				strcat(pNewBuf, sz);
				// 删掉原内存并指向新的字符串
				delete[] m_pBuff;
				m_pBuff = pNewBuf;
				m_nBuffSize = iTotalLen;
				m_nLen = iTotalLen - 1;
			}
			// 分配内存没成功, 什么也不用做
			else
			{
			}
		}
	}
	else
	{
		// m_pBuff为nullptr初始化调用了默认构造
		Init((char*)sz, iLen, iLen + 1, nullptr);
	}

	return(*this);
}

CMyString& 
CMyString::Append(
	const CMyString& sz
	)
{
	return(Append(sz.GetStr()));
}

CMyString& 
CMyString::Append(
	char ch
	)
{
	char szBuf[2] = { 0 };
	szBuf[0] = ch;
	return(Append(szBuf));
}

CMyString& 
CMyString::Append(
	int n
	)
{
	char szNumBuf[128] = { 0 };

	sprintf(szNumBuf, "%d", n);

	return(Append(szNumBuf));
}

CMyString& 
CMyString::Append(
	float f
	)
{
	char szNumBuf[128] = { 0 };

	sprintf(szNumBuf, "%f", f);

	return(Append(szNumBuf));
}

CMyString& 
CMyString::Append(
	double dbl
	)
{
	char szNumBuf[128] = { 0 };

	sprintf(szNumBuf, "%lf", dbl);

	return(Append(szNumBuf));
}

// 这里使用了朴素字符串匹配算法
int 
CMyString::Find(
	const char* sz
	)
{
	size_t uiLenOfDst = 0;
	size_t uiLenOfMod = 0;
	size_t uiCurPosOfDst = uiLenOfDst;
	size_t uiTotalLenOfMod = 0;
	size_t uiTotalLenOfDst = 0;

	if ((nullptr == sz) || (nullptr == m_pBuff))
	{
		return(-1);
	}

	uiTotalLenOfMod = strlen(sz);
	uiTotalLenOfDst = strlen(m_pBuff);

	do
	{
		if (uiTotalLenOfDst <= uiLenOfDst)
		{
			return(-1);
		}
		if (sz[uiLenOfMod] == m_pBuff[uiLenOfDst])
		{
			++uiLenOfDst;
			++uiLenOfMod;
			if (uiTotalLenOfMod <= uiLenOfMod)
			{
				return(uiLenOfDst - uiTotalLenOfMod);
			}
		}
		else
		{
			++uiCurPosOfDst;
			uiLenOfDst = uiCurPosOfDst;
			uiLenOfMod = 0;
		}
	} while (true);
}

int 
CMyString::Find(
	const CMyString& obj
	)
{
	return(Find(obj.m_pBuff));
}

int 
CMyString::ReverseFind(
    const char* sz
    )
{
	size_t uiLenOfsz = 0;
	int iPos = 0;
	char* pNewBuf = nullptr;

	uiLenOfsz = strlen(sz);
	pNewBuf = new char[uiLenOfsz + 1];
	memset(pNewBuf, 0, uiLenOfsz + 1);
	strcpy(pNewBuf, sz);
	ReverseString(pNewBuf);
	ReverseString(m_pBuff);

	iPos = Find(pNewBuf);
	ReverseString(m_pBuff);
	if (-1 == iPos)
	{
		return(iPos);
	}

	return(m_nLen - iPos - uiLenOfsz);
}

int 
CMyString::ReverseFind(
	const CMyString& obj
	)
{
	return(ReverseFind(obj.m_pBuff));
}

CMyString& 
CMyString::Copy(
	const char* sz
	)
{
	size_t uiLen = 0;

	if (nullptr == sz)
	{
		exit(1);
	}
	uiLen = strlen(sz);
	// 如果对象的字符缓冲区是nullptr需要重新分配
	if (nullptr == m_pBuff)
	{
		Init(m_pBuff, uiLen, uiLen + 1, nullptr);
	}
	else
	{
		delete[] m_pBuff;
		m_pBuff = new char[uiLen + 1];
		memset(m_pBuff, 0, uiLen + 1);
		strcpy(m_pBuff, sz);
		m_nLen = uiLen;
		m_nBuffSize = uiLen + 1;
	}

	return(*this);
}

CMyString& 
CMyString::Copy(
	const CMyString& obj
	)
{
	Copy(obj.m_pBuff);

	return(*this);
}

int 
CMyString::Compare(
	const char* sz
	)
{
	size_t uiNumOfStr = 0;
	size_t uiIndex = 0;

	if (nullptr == sz)
	{
		exit(1);
	}

	uiNumOfStr = strlen(sz);

	if (m_nLen != uiNumOfStr)
	{
		return(m_nLen - uiNumOfStr);
	}
	for (uiIndex = 0; uiIndex < uiNumOfStr; ++uiIndex)
	{
		if (m_pBuff[uiIndex] != sz[uiIndex])
		{
			return(m_pBuff[uiIndex] - sz[uiIndex]);
		}
	}

	return(0);
}

int 
CMyString::Compare(
	const CMyString& obj
	)
{
	return(Compare(obj.m_pBuff));
}

CMyString 
CMyString::Left(
	size_t nCount
	)
{
	CMyString CStr;
	char* pNewBuf = nullptr;

	// 如果当前对象没内容则直接返回空的对象
	if (nullptr == m_pBuff || (m_nLen <= 0))
	{
		return(CStr);
	}
	// 如果当前对象字符总字数小于要求的字符数量,则直接浅拷贝
	if ((m_nLen > 0) && (m_nLen <= nCount))
	{
		CStr.Init(m_pBuff, m_nLen, m_nBuffSize, m_pSize_t_Cnt);
		return(CStr);
	}
	else
	{
		pNewBuf = new char[nCount + 1];
		memset(pNewBuf, 0, nCount + 1);
		strncpy(pNewBuf, m_pBuff, nCount);
		CStr.Init(pNewBuf, nCount, nCount + 1, nullptr);
		return(CStr);
	}
}

CMyString 
CMyString::Right(
	size_t nCount
	)
{
	CMyString CStr;
	char* pNewBuf = nullptr;

	// 如果当前对象没内容则直接返回空的对象
	if (nullptr == m_pBuff || (m_nLen <= 0))
	{
		return(CStr);
	}

	// 如果当前对象字符总字数小于要求的字符数量,则直接浅拷贝
	if ((m_nLen > 0) && (m_nLen <= nCount))
	{
		CStr.Init(m_pBuff, m_nLen, m_nBuffSize, m_pSize_t_Cnt);
		return(CStr);
	}
	else
	{
		pNewBuf = new char[nCount + 1];
		memset(pNewBuf, 0, nCount + 1);
		size_t uiLen = strlen(m_pBuff);
		memcpy(pNewBuf, m_pBuff + uiLen - nCount, nCount);
		CStr.Init(pNewBuf, nCount, nCount + 1, nullptr);
		return(CStr);
	}
}

CMyString 
CMyString::Mid(
	int nIdx, 
	size_t nCount
	)
{
	char* pBuf = nullptr;

	if (nIdx + nCount > m_nLen)
	{
		return(CMyString());
	}
	pBuf = new char[nCount + 1];
	if (nullptr == pBuf)
	{
		return(CMyString());
	}
	memset(pBuf, 0, nCount + 1);
	memcpy(pBuf, m_pBuff + nIdx, nCount);

	CMyString strRet(pBuf);
	delete[] pBuf;

	return(strRet);
	//CMyString CStr;
	//char* pNewBuf = nullptr;

	 如果当前对象没内容则直接返回空的对象
	//if (nullptr == m_pBuff || (m_nLen <= 0))
	//{
	//	return(CStr);
	//}
	 判定参数是否符合规定
	//if ((nIdx >= m_nLen) || (m_nLen < (nIdx + nCount)))
	//{
	//	return(CStr);
	//}
	//CStr.Init(m_pBuff + nIdx, nCount, nCount + 1, nullptr);

	//return(CStr);
}

CMyString 
CMyString::ValueOf(
	bool fBoolean
	)
{
	CMyString CStr;
	char szTrueBuf[] = "true";
	char szFalseBuf[] = "false";

	CStr.Init(
		(fBoolean ? szTrueBuf : szFalseBuf),  
		(fBoolean ? strlen(szTrueBuf) : strlen(szFalseBuf)),
		(fBoolean ? (strlen(szTrueBuf) + 1) : (strlen(szFalseBuf) + 1)),
		nullptr 
		);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
	char c
	)
{
	return(CMyString(c));
}

CMyString 
CMyString::ValueOf(
    double d
    )
{
	char szBuf[64] = { 0 };
	size_t uiLen = 0;
	CMyString CStr;

	sprintf(szBuf, "%lf", d);
	uiLen = strlen(szBuf);
	CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
    float f
    )
{
	char szBuf[64] = { 0 };
	size_t uiLen = 0;
	CMyString CStr;

	sprintf(szBuf, "%f", f);
	uiLen = strlen(szBuf);
	CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
    int i
    )
{
	char szBuf[64] = { 0 };
	size_t uiLen = 0;
	CMyString CStr;

	sprintf(szBuf, "%d", i);
	uiLen = strlen(szBuf);
	CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
    long i
    )
{
	char szBuf[64] = { 0 };
	size_t uiLen = 0;
	CMyString CStr;

	sprintf(szBuf, "%ld", i);
	uiLen = strlen(szBuf);
	CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
    short i
    )
{
	char szBuf[64] = { 0 };
	size_t uiLen = 0;
	CMyString CStr;

	sprintf(szBuf, "%hd", i);
	uiLen = strlen(szBuf);
	CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);

	return(CStr);
}

CMyString 
CMyString::ValueOf(
    const char* data
    )
{
	CMyString CStr(data);

	return(CStr);
}

CMyString 
CMyString::CopyValueOf(
    const char* data, 
    int offset, 
    int count
    )
{
	CMyString CStr(data);

	return(CStr.Mid(offset, count));
}

CMyString 
CMyString::StringFromFormat(
    const char* format, 
    ...
    )
{
	va_list vl;
	va_start(vl, format);

	int iSize = _vscprintf(format, vl) + 1;
	char* pBuff = new char[iSize];
	memset(pBuff, 0, iSize);
	vsprintf(pBuff, format, vl);
	va_end(vl);

	CMyString strRet(pBuff);

	// delete[]pBuff;

	return(strRet);
}

bool 
CMyString::Init(
	char* pBuff, 
	size_t size_t_Len, 
	size_t size_t_BufSize,
	size_t *pSize_t_Cnt
	)
// 只有在指针未分配情况下才可以用此函数初始化
// 假设由于形参问题出了错,在构造情况下会直接调用默认构造,如果是拷贝情况形参是不大可能(除非人为)出错
// 因为拷贝构造必定是由另一个对象进行拷贝的, 那个对象的类成员必定符合要求
{
	do
	{
		if (nullptr == pBuff)
		{
			break;
		}
		if (size_t_Len >= size_t_BufSize)
		{
			break;
		}

		m_nLen = size_t_Len;
		m_nBuffSize = size_t_BufSize;
		// 这里代表是构造进来的, 需要重新构造
		if (nullptr == pSize_t_Cnt)
		{
			m_pBuff = new char[size_t_BufSize];
			if (nullptr == m_pBuff)
			{
				break;
			}
			memset(m_pBuff, 0, size_t_BufSize);
			strcpy(m_pBuff, pBuff);
			m_pSize_t_Cnt = new size_t(1);
			if (nullptr == m_pSize_t_Cnt)
			{
				delete[] m_pBuff;
				m_pBuff = nullptr;
			}
		}
		// 这里代表是拷贝构造进来的, 仅浅拷贝+提升引用计数
		else
		{
			m_pBuff = pBuff;
			m_pSize_t_Cnt = pSize_t_Cnt;
			++(*m_pSize_t_Cnt);
		}
	} while (false);

	if (nullptr == m_pBuff)
	{
		ZeroMemory(this);
		return(false);
	}

	return(true);
}

void 
CMyString::SetStr(
	const char* sz
	)
{
	int iLen = 0;

	if (nullptr == sz)
	{
		return;
	}

	iLen = strlen(sz);
	
	if (nullptr == m_pBuff)
	{
		//
		//
		//
		//
	}
}

void 
CMyString::ZeroMemory(
	CMyString* pCStr
	)
{
	if (nullptr == pCStr)
	{
		return;
	}

	pCStr->m_nBuffSize = 0;
	pCStr->m_nLen = 0;
	pCStr->m_pBuff = nullptr;
	pCStr->m_pSize_t_Cnt = nullptr;
}

最后是测试用的main函数:

#include <iostream>
#include <cstdlib>
#include "CMyString.h"

using namespace std;

int main()
{
    CMyString CMyStr("Hello, world!");
    int iNum = 128;
    long lNum = 128;
    short sNum = 128;

    if (CMyStr.Compare("Hello, world!"))
    {
        cout << "不相等" << endl;
    }
    else
    {
        cout << "相等" << endl;
    }
    CMyStr.Copy("the word the the!");
    cout << CMyStr.GetStr();

    cout << CMyStr.Left(4).GetStr();
    cout << CMyStr.Right(6).GetStr();
    cout << CMyStr.Find("the");
    cout << CMyStr.ReverseFind("the");
    cout << CMyStr.GetStr() << endl;

    cout << CMyString::ValueOf(false).GetStr() << endl;
    cout << CMyString::ValueOf(4.15).GetStr() << endl;
    cout << CMyString::ValueOf(5.162f).GetStr() << endl;
    cout << CMyString::ValueOf(iNum).GetStr() << endl;
    cout << CMyString::ValueOf(lNum).GetStr() << endl;
    cout << CMyString::ValueOf(sNum).GetStr() << endl;
    cout << CMyString::ValueOf("Back Off").GetStr() << endl;
    
    cout << CMyStr.Mid(5, 3).GetStr() << endl;
    CMyString str = CMyStr.CopyValueOf("Hello, world", 7, 5);
    cout << str.GetStr();
    cout << str.StringFromFormat("%s %s", "What", "the").GetStr();

    str.Append("Fuck the world").Append(3.14).Append(555);
    cout << str.GetStr();

    system("pause");

    return(0);
}

(完)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值