接口对比表格
功能分类 |
你的 CString 接口 |
MFC CString 接口(ANSI) |
一致性 |
差异说明 |
构造函数 |
CString() |
CString() |
一致 |
MFC 使用 LPCSTR(const char*),命名和参数逻辑相同。 |
析构函数 |
~CString() |
~CString() |
一致 |
均需手动释放内存(MFC 内部自动管理 COW 缓冲区)。 |
长度与判空 |
int GetLength() const |
int GetLength() const |
一致 |
MFC 返回 BOOL(等效 bool),功能相同。 |
字符访问 |
char GetAt(int) const |
TCHAR GetAt(int) const |
一致 |
MFC 使用 TCHAR(char in ANSI),越界处理:MFC 断言,你抛出异常。 |
修改字符 |
void SetAt(int, char) |
void SetAt(int, TCHAR) |
一致 |
参数和逻辑相同。 |
查找操作 |
int Find(char) const |
int Find(TCHAR) const |
一致 |
MFC 参数为 LPCTSTR(const char*),功能相同。 |
替换操作 |
int Replace(char, char) |
int Replace(TCHAR, TCHAR) |
一致 |
均返回替换次数,字符串替换需动态扩容。 |
删除操作 |
int Remove(char) |
int Remove(TCHAR) |
一致 |
均返回删除次数,逻辑相同。 |
插入操作 |
int Insert(int, char) |
int Insert(int, TCHAR) |
一致 |
参数和返回值(新长度)相同,MFC 支持 CString 插入(通过 LPCTSTR 兼容)。 |
删除子串 |
int Delete(int, int = 1) |
int Delete(int, int = 1) |
一致 |
默认删除 1 个字符,越界处理逻辑需确保安全。 |
子串操作 |
CString Left(int) const |
CString Left(int) const |
一致 |
均返回子串对象,处理越界时返回空串。 |
赋值运算符 |
CString& operator=(char) |
CString& operator=(TCHAR) |
一致 |
MFC 无非常量引用赋值,你已删除 operator=(CString&),与 MFC 一致。 |
追加运算符 |
CString& operator+=(char) |
CString& operator+=(TCHAR) |
一致 |
功能相同,MFC 通过 LPCTSTR 兼容 CString。 |
连接运算符 |
friend CString operator+(...)(多重载) |
friend CString operator+(...)(多重载) |
一致 |
均支持字符串连接,返回新对象。 |
比较运算符 |
friend bool operator==/!=/>/<>=/<=(...) |
friend BOOL operator==/!=/>/<>=/<=(...) |
一致 |
MFC 返回 BOOL,逻辑相同;支持与 const char* 比较。 |
格式化 |
void Format(const char*, ...) |
void Format(LPCTSTR, ...) |
一致 |
均基于 sprintf,MFC 支持更多格式符(如 %I64d)。 |
大小写转换 |
void MakeUpper() |
void MakeUpper() |
部分一致 |
MFC 支持本地化转换(如土耳其语),你仅实现 ASCII 转换。 |
去除空白字符 |
void TrimLeft() |
void TrimLeft() |
部分一致 |
MFC 默认识别所有空白字符(如制表符),你的实现依赖 isspace(一致)。 |
反转字符串 |
CString& MakeReverse() |
CStringT& MakeReverse() |
一致 |
MFC 通过 StringTraits::StringReverse 实现,你通过手动交换字符实现,功能相同。 |
内存管理接口 |
char* GetBuffer(int) |
LPTSTR GetBuffer(int) |
差异 |
你未提供 ReleaseBuffer(),需手动管理长度;MFC 通过 ReleaseBuffer() 自动更新。 |
高级功能 |
无 Tokenize/LoadString/ 路径处理等 |
支持 Tokenize/LoadString/ExtractFilePath 等 |
缺失 |
MFC 提供字符串分词、资源加载、路径解析等高级功能。 |
安全检查 |
部分函数抛出异常(如越界) |
部分函数内部断言(如 ATLASSERT) |
差异 |
MFC 依赖调试断言,你使用异常处理,均实现基本安全控制。 |
关键结论
1.基础操作完全一致:
构造 / 析构、查找 / 替换、比较 / 连接等核心接口的命名、参数和功能与 MFC 一致,可直接映射。
2.const 修饰完全对齐:
所有 const 成员函数、参数均符合 MFC 规范,类型安全无差异。
差异与缺失:
- 内存管理:缺少 ReleaseBuffer(),需手动处理 GetBuffer() 后的长度更新。
- 高级功能:无 Tokenize、资源加载、路径处理等 MFC 特有功能。
- 本地化:大小写转换未考虑区域设置,MFC 支持更全面。
适用场景:
- 一致场景:ANSI 环境下的基础字符串操作,如简单文本处理、非国际化逻辑。
- 不一致场景:需要 Unicode、高性能内存管理(COW)、复杂字符串处理(如路径解析)的场景。
cstring.h
#ifndef CSTRING_H
#define CSTRING_H
#include <cstdarg>
class CString
{
public:
//默认构造函数
CString();
//析构函数
~CString();
//从另一个 CString 复制构造
CString(const CString& string1);
// 从C风格字符串构造
CString(const char *ch);
// 从单个字符构造
CString(const char ch);
// 获取字符串长度
int GetLength() const;
// 判断字符串是否为空
bool IsEmpty() const;
// 清空字符串
void Empty();
// 获取指定位置的字符
char GetAt(int iIndex) const;
//重载 [] 运算符
char& operator[](int iIndex);
//重载 [] 运算符
const char& operator[](int iIndex) const;
//修改指定位置的字符
void SetAt(int iIndex, char ch);
// 查找字符最后一次出现的位置,失败返回-1
int ReverseFind(char ch) const;
// 替换所有指定字符,返回替换次数
int Replace(char chOld, char chNew);
// 替换所有子字符串,返回替换次数
int Replace(const char* lpszOld, const char* lpszNew);
// 删除所有指定字符,返回删除次数
int Remove(char ch);
// 在字符串的 nIndex 位置插入字符 ch,返回插入字符后字符串的长度
int Insert(int nIndex, char ch);
// 在字符串的 nIndex 位置插入字符串 lpsz,返回插入字符串后字符串的长度
int Insert(int nIndex, char* lpsz);
// 删除字符串中从 nIndex 位置开始的 nCount 个字符(默认删除 1 个字符),返回删除字符后字符串的长度
int Delete(int nIndex, int nCount = 1);
// 字符赋值运算符重载
CString& operator=(char ch);
// C风格字符串赋值运算符重载
CString& operator=(const char * lpsz);
// 常量CString拷贝赋值运算符重载
CString& operator=(const CString& string1);
// 字符追加运算符重载
CString& operator+=(char ch);
// C风格字符串追加运算符重载
CString& operator+=(const char *str);
// CString追加运算符重载
CString& operator+=(const CString &Str);
// 格式化字符串,功能类似sprintf,返回格式化后的长度
void Format(const char* pstrFormat, ...);
// 截取左边n个字符的子串
CString Left(int nCount) const;
// 截取右边n个字符的子串
CString Right(int nCount) const;
// 从nFirst开始到末尾的子串
CString Mid(int nFirst) const;
// 从nFirst开始截取nCount个字符的子串
CString Mid(int nFirst, int nCount) const;
// 获取内部缓冲区指针,用于直接操作内存
char* GetBuffer(int nMinBufLength);
// 查找
int Find(char ch) const;
int Find(const char * lpszSub) const;
int Find(char ch, int nStart) const;
int Find(const char *str, int uiBegin) const;
int Find(CString sSub) const;
int FindOneOf(const char* lpszCharSet) const;
// 转换为大写
void MakeUpper();
// 转换为小写
void MakeLower();
// 去除左侧空白字符
void TrimLeft();
// 去除右侧空白字符
void TrimRight();
// 去除两侧空白字符
void Trim();
//反转
CString & MakeReverse();
//用于比较的函数
int Compare(const char *str)const;
int Compare(const CString &Str)const;
int CompareNoCase(const char *str)const;
int CompareNoCase(const CString &Str)const;
// 连接两个CString对象,返回新对象
friend CString operator+(const CString& string1, const CString& string2);
friend CString operator+(const CString& string1, char ch);
friend CString operator+(const CString& string1, const char* ch);
friend CString operator+(const char *str, const CString &Str);
friend CString operator+(char ch, const CString &Str);
// 判断CString与C风格字符串是否相等
friend bool operator==(const CString& string1, const char* ch);
friend bool operator==(const CString& string1, const CString& string2);
friend bool operator==(const char *str, const CString &Str);
// 判断两个CString对象是否不相等
friend bool operator!=(const CString& string1, const char* ch);
friend bool operator!=(const CString& string1, const CString& string2);
friend bool operator!=(const char *str, const CString &Str);
// 比较两个CString对象大小(大于)
friend bool operator> (const CString &Str1, const CString &Str2);
friend bool operator> (const CString &Str, const char *str);
friend bool operator> (const char *str, const CString &Str);
// 比较两个CString对象大小(大于等于)
friend bool operator>= (const CString &Str1, const CString &Str2);
friend bool operator>=(const CString &Str, const char *str);
friend bool operator>=(const char *str, const CString &Str);
// 比较两个CString对象大小(小于)
friend bool operator< (const CString &Str1, const CString &Str2);
friend bool operator< (const CString &Str, const char *str);
friend bool operator< (const char *str, const CString &Str);
// 比较两个CString对象大小(小于等于)
friend bool operator<= (const CString &Str1, const CString &Str2);
friend bool operator<=(const CString &Str, const char *str);
friend bool operator<=(const char *str, const CString &Str);
private:
// 字符串缓冲区指针(以'\0'结尾)
char* m_pBuf;
// 当前字符串长度(不包含终止符)
int m_iLen;
};
#endif // CSTRING_H
cstring.cpp
#include "CString.h"
#include <cstring>
#include <cstdarg>
#include <cassert>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <stdexcept> // 添加这个头文件以使用 std::out_of_range
// 默认构造函数
CString::CString()
: m_pBuf(nullptr)
, m_iLen(0)
{
m_pBuf = new char[1];
m_pBuf[0] = '\0'; // 初始化空字符串
}
// 从C风格字符串构造
CString::CString(const char* lpsz)
: m_pBuf(nullptr)
, m_iLen(0)
{
if(lpsz)
{
m_iLen = strlen(lpsz);
m_pBuf = new char[m_iLen + 1];
strcpy(m_pBuf, lpsz);
}
else
{
// 处理空指针输入
m_pBuf = new char[1];
m_pBuf[0] = '\0';
}
}
// 从单个字符构造
CString::CString(char ch)
: m_pBuf(nullptr)
, m_iLen(1)
{
m_pBuf = new char[2];
m_pBuf[0] = ch;
m_pBuf[1] = '\0';
}
// 拷贝构造函数
CString::CString(const CString& src)
: m_pBuf(nullptr)
, m_iLen(src.m_iLen)
{
if(src.m_pBuf)
{
m_pBuf = new char[m_iLen + 1];
strcpy(m_pBuf, src.m_pBuf);
}
else
{
// 理论上不会执行,因为m_pBuf在其他构造函数中已初始化
m_pBuf = new char[1];
m_pBuf[0] = '\0';
}
}
//析构函数
CString::~CString()
{
delete[] m_pBuf;
m_pBuf = nullptr;
}
// 获取指定索引位置的字符
char CString::GetAt(int iIndex) const
{
if(iIndex >= m_iLen || iIndex < 0)
{
// 越界时抛出异常
throw std::out_of_range("Index out of range in GetAt");
}
return m_pBuf[iIndex];
}
//修改指定位置的字符
void CString::SetAt(int iIndex, char ch)
{
if(iIndex >= m_iLen || iIndex < 0)
{
// 越界时抛出异常
throw std::out_of_range("Index out of range in SetAt");
}
m_pBuf[iIndex] = ch;
}
// 字符赋值运算符重载
CString& CString::operator=(char ch)
{
// 释放原有内存
delete[] m_pBuf;
// 分配新内存(1个字符+终止符)
m_iLen = 1;
m_pBuf = new char[2];
m_pBuf[0] = ch;
m_pBuf[1] = '\0';
return *this;
}
// C风格字符串赋值运算符重载
CString& CString::operator =(const char * lpsz)
{
// 释放原有内存
delete[] m_pBuf;
if(lpsz)
{
// 复制新字符串
m_iLen = strlen(lpsz);
m_pBuf = new char[m_iLen + 1];
strcpy(m_pBuf, lpsz);
}
else
{
// 处理空指针(赋值为空字符串)
m_iLen = 0;
m_pBuf = new char[1];
m_pBuf[0] = '\0';
}
return *this;
}
// 常量CString拷贝赋值运算符重载
CString& CString::operator=(const CString& string1)
{
if(this != &string1) // 防止自赋值
{
// 释放原有内存
delete[] m_pBuf;
// 复制新字符串
m_iLen = string1.m_iLen;
if(m_iLen > 0)
{
m_pBuf = new char[m_iLen + 1];
strcpy(m_pBuf, string1.m_pBuf);
}
else
{
m_pBuf = new char[1];
m_pBuf[0] = '\0';
}
}
return *this;
}
// 字符追加运算符重载
CString& CString::operator+=(char ch)
{
// 计算新长度
int newLen = m_iLen + 1;
// 分配新内存
char* newBuf = new char[newLen + 1];
// 复制原有内容
if(m_iLen > 0)
{
strcpy(newBuf, m_pBuf);
}
else
{
newBuf[0] = '\0'; // 确保空字符串以'\0'开头
}
// 添加字符
newBuf[m_iLen] = ch;
newBuf[newLen] = '\0'; // 终止字符串
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen = newLen;
return *this;
}
// C风格字符串追加运算符重载
CString& CString::operator+=(const char *str)
{
if(str && *str) // 检查str不为空指针且不为空字符串
{
int len = strlen(str);
int newLen = m_iLen + len;
// 分配新内存
char* newBuf = new char[newLen + 1];
// 复制原有内容
if(m_iLen > 0)
{
strcpy(newBuf, m_pBuf);
}
else
{
newBuf[0] = '\0'; // 确保空字符串以'\0'开头
}
// 追加新字符串
strcat(newBuf, str);
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen = newLen;
}
return *this;
}
// CString追加运算符重载
CString& CString::operator+=(const CString &Str)
{
if(Str.m_iLen > 0) // 检查Str不为空字符串
{
int newLen = m_iLen + Str.m_iLen;
// 分配新内存
char* newBuf = new char[newLen + 1];
// 复制原有内容
if(m_iLen > 0)
{
strcpy(newBuf, m_pBuf);
}
else
{
newBuf[0] = '\0'; // 确保空字符串以'\0'开头
}
// 追加新字符串
strcat(newBuf, Str.m_pBuf);
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen = newLen;
}
return *this;
}
// 格式化字符串,功能类似sprintf,返回格式化后的长度
void CString::Format(const char* pstrFormat, ...)
{
if(!pstrFormat)
{
Empty();
return ;
}
va_list args;
va_start(args, pstrFormat);
// 第一次调用 vsnprintf 计算所需缓冲区大小
int requiredLen = vsnprintf(nullptr, 0, pstrFormat, args);
va_end(args);
// 错误处理:检查 vsnprintf 的返回值
if(requiredLen < 0)
{
// 处理格式化错误(例如格式字符串包含无效格式说明符)
Empty();
// 可选择抛出异常或设置错误标志
throw std::runtime_error("Format error: invalid format string");
// 或者返回错误码(需要修改函数返回类型)
return ;
}
// 分配内存
char* newBuf = new char[requiredLen + 1];
// 第二次调用 vsnprintf 格式化字符串
va_start(args, pstrFormat);
int actualWritten = vsnprintf(newBuf, requiredLen + 1, pstrFormat, args);
va_end(args);
// 再次检查返回值(理论上不会失败,但为了健壮性)
if(actualWritten < 0 || actualWritten > requiredLen)
{
delete[] newBuf;
Empty();
throw std::runtime_error("Format error: unexpected write failure");
}
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen = requiredLen;
return ;
}
// 返回字符串长度(不包含终止符)
int CString::GetLength() const
{
return m_iLen;
}
// 截取左边nCount个字符的子串
CString CString::Left(int nCount) const
{
CString result;
// 处理无效参数
if(nCount <= 0)
{
return result; // 返回空字符串
}
// 限制截取长度不超过原字符串长度
int actualCount = (nCount > m_iLen) ? m_iLen : nCount;
// 分配内存并复制子串
delete[] result.m_pBuf;
result.m_pBuf = new char[actualCount + 1];
memcpy(result.m_pBuf, m_pBuf, actualCount);
result.m_pBuf[actualCount] = '\0'; // 添加终止符
result.m_iLen = actualCount;
return result;
}
// 截取右边nCount个字符的子串
CString CString::Right(int nCount) const
{
CString result;
// 处理无效参数
if(nCount <= 0)
{
return result; // 返回空字符串
}
// 限制截取长度不超过原字符串长度
int actualCount = (nCount > m_iLen) ? m_iLen : nCount;
int startPos = m_iLen - actualCount; // 计算起始位置
// 分配内存并复制子串
delete[] result.m_pBuf;
result.m_pBuf = new char[actualCount + 1];
memcpy(result.m_pBuf, m_pBuf + startPos, actualCount);
result.m_pBuf[actualCount] = '\0'; // 添加终止符
result.m_iLen = actualCount;
return result;
}
// 从nFirst开始到末尾的子串
CString CString::Mid(int nFirst) const
{
CString result;
// 处理无效参数(负数或超出长度)
if(nFirst < 0 || nFirst >= m_iLen)
{
return result; // 返回空字符串
}
// 计算子串长度
int subLen = m_iLen - nFirst;
// 分配内存并复制子串
delete[] result.m_pBuf;
result.m_pBuf = new char[subLen + 1];
memcpy(result.m_pBuf, m_pBuf + nFirst, subLen);
result.m_pBuf[subLen] = '\0'; // 添加终止符
result.m_iLen = subLen;
return result;
}
// 从nFirst开始截取nCount个字符的子串
CString CString::Mid(int nFirst, int nCount) const
{
CString result;
// 处理无效参数
if(nFirst < 0 || nFirst >= m_iLen || nCount <= 0)
{
return result; // 返回空字符串
}
// 计算实际截取长度(避免越界)
int actualCount = nCount;
if(nFirst + actualCount > m_iLen)
{
actualCount = m_iLen - nFirst;
if(actualCount <= 0) return result; // 起始位置已超出末尾
}
// 分配内存并复制子串
delete[] result.m_pBuf;
result.m_pBuf = new char[actualCount + 1];
memcpy(result.m_pBuf, m_pBuf + nFirst, actualCount);
result.m_pBuf[actualCount] = '\0'; // 添加终止符
result.m_iLen = actualCount;
return result;
}
// 判断字符串是否为空
bool CString::IsEmpty() const
{
return (m_iLen == 0);
}
// 清空字符串内容
void CString::Empty()
{
// 释放原有内存
delete[] m_pBuf;
m_pBuf = nullptr;
// 重置为初始状态(空字符串)
m_iLen = 0;
m_pBuf = new char[1];
m_pBuf[0] = '\0';
}
// 获取内部缓冲区指针,用于直接操作内存
char* CString::GetBuffer(int nMinBufLength)
{
if(nMinBufLength < 0 || nMinBufLength > m_iLen)
{
return nullptr;
}
return m_pBuf + nMinBufLength;
}
//查找字符首次出现的位置,失败返回-1
int CString::Find(char ch) const
{
for(int i = 0; i < m_iLen; i++)
{
if(m_pBuf[i] == ch)
{
return i;
}
}
return -1;
}
int CString::Find(char ch, int nStart) const
{
// 检查起始位置是否合法
if(nStart < 0 || nStart >= m_iLen)
return -1;
// 从nStart位置开始查找字符ch
for(int i = nStart; i < m_iLen; i++)
{
if(m_pBuf[i] == ch)
return i; // 找到字符,返回其位置
}
return -1; // 未找到字符
}
//查找子字符串首次出现的位置,失败返回-1
int CString::Find(const char* lpszSub) const
{
if(!lpszSub || !*lpszSub) return -1; // 处理空指针或空字符串
int subLen = strlen(lpszSub);
if(subLen > m_iLen) return -1; // 子串长度超过原字符串
const char* pos = strstr(m_pBuf, lpszSub);
if(pos)
{
return pos - m_pBuf; // 计算相对位置
}
return -1; // 未找到匹配子串
}
//查找CString对象首次出现的位置,失败返回-1
int CString::Find(CString sSub) const
{
if(sSub.IsEmpty()) return -1;
return Find(sSub.GetBuffer(0));
}
//从索引uiBegin开始,返回字符串str第一次出现的位置,省略uiBegin使其为默认的0,未找到返回-1
int CString::Find(const char *str, int uiBegin) const
{
if(!str || !*str) return -1; // 空字符串直接返回-1
int lenStr = strlen(str);
if(lenStr > m_iLen) return -1; // 查找的字符串比原字符串长
// 处理无效的起始位置
if(uiBegin < 0) uiBegin = 0;
if(uiBegin > m_iLen - lenStr) return -1; // 剩余长度不足
const char *pStart = m_pBuf + uiBegin;
const char *pEnd = m_pBuf + m_iLen - lenStr + 1;
// 使用strstr进行高效查找
const char *pFound = strstr(pStart, str);
if(pFound && pFound < pEnd)
{
return pFound - m_pBuf; // 计算相对位置
}
return -1; // 未找到匹配的子字符串
}
// 连接两个CString对象,返回新对象
CString operator+(const CString& string1, const CString& string2)
{
int len1 = string1.GetLength();
int len2 = string2.GetLength();
char* pchar = new char[len1 + len2 + 1];
memset(pchar, '\0', len1 + len2 + 1);
// 直接访问m_pBuf
memcpy(pchar, string1.m_pBuf, len1);
memcpy(pchar + len1, string2.m_pBuf, len2);
CString strTemp(pchar);
delete[] pchar;
return strTemp;
}
// CString连接字符,返回新对象
CString operator+(const CString& string1, char ch)
{
int len1 = string1.GetLength();
char* pchar = new char[len1 + 2];
memset(pchar, '\0', len1 + 2);
memcpy(pchar, string1.m_pBuf, len1);
pchar[len1] = ch;
CString strTemp(pchar);
delete[] pchar;
return strTemp;
}
// CString连接C风格字符串,返回新对象
CString operator+(const CString& string1, const char* ch)
{
if(!ch)
{
return CString("");
}
int len1 = string1.GetLength();
int len2 = strlen(ch);
char* buffer = new char[len1 + len2 + 1];
memcpy(buffer, string1.m_pBuf, len1);
memcpy(buffer + len1, ch, len2);
buffer[len1 + len2] = '\0';
CString result(buffer);
delete[] buffer;
return result;
}
// 实现字符串常量与CString相加
CString operator+ (const char *str, const CString &Str)
{
if(str == nullptr) return CString(Str);
int len = strlen(str);
CString result;
result.m_iLen = len + Str.m_iLen;
result.m_pBuf = new char[result.m_iLen + 1];
strcpy(result.m_pBuf, str);
strcat(result.m_pBuf, Str.m_pBuf);
return result;
}
// 实现字符与CString相加
CString operator+ (char ch, const CString &Str)
{
CString result;
result.m_iLen = 1 + Str.m_iLen;
result.m_pBuf = new char[result.m_iLen + 1];
result.m_pBuf[0] = ch;
strcpy(result.m_pBuf + 1, Str.m_pBuf);
result.m_pBuf[result.m_iLen] = '\0';
return result;
}
// 判断CString与C风格字符串是否不相等
bool operator!=(const CString& string1, const char* ch)
{
// 处理ch为nullptr的情况
if(!ch)
{
return !string1.IsEmpty(); // string1非空时返回true
}
// 使用strcmp比较内容
return strcmp(string1.m_pBuf, ch) != 0;
}
// 判断CString与C风格字符串是否相等
bool operator==(const CString& string1, const char* ch)
{
// 处理ch为nullptr的情况
if(!ch)
{
return string1.IsEmpty(); // string1为空时返回true
}
// 使用strcmp比较内容
return strcmp(string1.m_pBuf, ch) == 0;
}
// 判断两个CString对象是否相等
bool operator==(const CString& string1, const CString& string2)
{
if(string1.GetLength() != string2.GetLength())
{
return false;
}
return strcmp(string1.m_pBuf, string2.m_pBuf) == 0;
}
bool operator==(const char *str, const CString &Str)
{
// 处理str为nullptr的情况
if(str == nullptr)
{
return Str.m_iLen == 0; // nullptr只能与空字符串相等
}
// 比较长度是否一致
if(strlen(str) != Str.m_iLen)
{
return false;
}
// 逐个字符比较内容
return strncmp(str, Str.m_pBuf, Str.m_iLen) == 0;
}
// 判断两个CString对象是否不相等
bool operator!=(const CString& string1, const CString& string2)
{
// 长度不同则直接不相等
if(string1.GetLength() != string2.GetLength())
{
return true;
}
// 使用strcmp比较内容
return strcmp(string1.m_pBuf, string2.m_pBuf) != 0;
}
//将字符串转化为一个大写的字符串
void CString::MakeUpper()
{
for(int i = 0; i < m_iLen; i++)
{
if(m_pBuf[i] >= 'a' && m_pBuf[i] <= 'z')
{
m_pBuf[i] -= 32; // 转换为大写(ASCII码差值为32)
}
}
}
//将字符串转化为一个小写的字符串
void CString::MakeLower()
{
for(int i = 0; i < m_iLen; i++)
{
if(m_pBuf[i] >= 'A' && m_pBuf[i] <= 'Z')
{
m_pBuf[i] += 32; // 转换为小写(ASCII码差值为32)
}
}
}
void CString::TrimLeft()
{
int i = 0;
// 查找第一个非空白字符的位置
while(m_pBuf[i] != '\0' && isspace(m_pBuf[i]))
i++;
// 如果存在前导空白字符,则移动字符串
if(i > 0)
{
memmove(m_pBuf, m_pBuf + i, m_iLen - i + 1); // 包含终止符'\0'
m_iLen -= i;
}
}
void CString::TrimRight()
{
int i = m_iLen - 1;
// 查找最后一个非空白字符的位置
while(i >= 0 && isspace(m_pBuf[i]))
i--;
// 如果存在尾部空白字符,则设置新的字符串长度并添加终止符
if(i < m_iLen - 1)
{
m_iLen = i + 1;
m_pBuf[m_iLen] = '\0';
}
}
//去掉左右两边的空格
void CString::Trim()
{
TrimLeft();
TrimRight();
}
// 比较两个CString对象大小(大于)
bool operator>(const CString &Str1, const CString &Str2)
{
return strcmp(Str1.m_pBuf, Str2.m_pBuf) > 0;
}
// 比较两个CString对象大小(小于)
bool operator<(const CString &Str1, const CString &Str2)
{
return strcmp(Str1.m_pBuf, Str2.m_pBuf) < 0;
}
// 比较两个CString对象大小(大于等于)
bool operator>=(const CString &Str1, const CString &Str2)
{
return strcmp(Str1.m_pBuf, Str2.m_pBuf) >= 0;
}
// 比较两个CString对象大小(小于等于)
bool operator<=(const CString &Str1, const CString &Str2)
{
return strcmp(Str1.m_pBuf, Str2.m_pBuf) <= 0;
}
// 下标运算符重载
char& CString::operator[](int iIndex)
{
if(iIndex >= m_iLen || iIndex < 0)
{
// 越界时抛出异常
throw std::out_of_range("Index out of range in operator[]");
}
return m_pBuf[iIndex];
}
// 常量版本的下标运算符重载
const char& CString::operator[](int iIndex) const
{
if(iIndex >= m_iLen || iIndex < 0)
{
// 越界时抛出异常
throw std::out_of_range("Index out of range in operator[] const");
}
return m_pBuf[iIndex];
}
//反转
CString& CString::MakeReverse()
{
int left = 0;
int right = m_iLen - 1;
while(left < right)
{
// 交换左右字符
char temp = m_pBuf[left];
m_pBuf[left] = m_pBuf[right];
m_pBuf[right] = temp;
left++;
right--;
}
return *this; // 返回自身引用,支持链式调用
}
// 查找字符最后一次出现的位置,失败返回-1
int CString::ReverseFind(char ch) const
{
for(int i = m_iLen - 1; i >= 0; i--)
{
if(m_pBuf[i] == ch)
{
return i;
}
}
return -1; // 未找到
}
// 替换所有指定字符,返回替换次数
int CString::Replace(char chOld, char chNew)
{
int count = 0;
for(int i = 0; i < m_iLen; i++)
{
if(m_pBuf[i] == chOld)
{
m_pBuf[i] = chNew;
count++;
}
}
return count;
}
// 替换所有子字符串,返回替换次数
int CString::Replace(const char* lpszOld, const char* lpszNew)
{
if(!lpszOld || !*lpszOld)
{
return 0;
}
if(!lpszNew)
{
throw std::invalid_argument("lpszNew is nullptr");
}
int lenOld = strlen(lpszOld);
int lenNew = strlen(lpszNew);
int count = 0;
// 计算替换后的新长度
int newLen = m_iLen;
const char* p = m_pBuf;
while((p = strstr(p, lpszOld)))
{
newLen += lenNew - lenOld;
p += lenOld;
count++;
}
if(count == 0) return 0; // 没有找到匹配项
// 分配新缓冲区
char* newBuf = new char[newLen + 1];
char* dest = newBuf;
const char* src = m_pBuf;
// 执行替换
while(*src)
{
if(strncmp(src, lpszOld, lenOld) == 0)
{
memcpy(dest, lpszNew, lenNew);
dest += lenNew;
src += lenOld;
}
else
{
*dest++ = *src++;
}
}
*dest = '\0'; // 终止字符串
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen = newLen;
return count;
}
// 删除所有指定字符,返回删除次数
int CString::Remove(char ch)
{
int count = 0;
char* dest = m_pBuf;
for(int i = 0; i < m_iLen; i++)
{
if(m_pBuf[i] != ch)
{
*dest++ = m_pBuf[i];
}
else
{
count++;
}
}
*dest = '\0'; // 终止字符串
m_iLen -= count;
return count;
}
// 在指定位置插入字符,返回新字符串长度
int CString::Insert(int nIndex, char ch)
{
if(nIndex < 0)
{
throw std::out_of_range("Insert position is negative");
}
if(nIndex > m_iLen)
{
throw std::out_of_range("Insert position is greater than the current length");
}
// 分配新缓冲区
char* newBuf = new char[m_iLen + 2]; // +1 为插入的字符,+1 为终止符
// 复制前半部分
memcpy(newBuf, m_pBuf, nIndex);
// 插入字符
newBuf[nIndex] = ch;
// 复制后半部分
memcpy(newBuf + nIndex + 1, m_pBuf + nIndex, m_iLen - nIndex);
// 终止字符串
newBuf[m_iLen + 1] = '\0';
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen++;
return m_iLen;
}
// 在指定位置插入字符串,返回新字符串长度
int CString::Insert(int nIndex, char* lpsz)
{
if(!lpsz)
{
throw std::invalid_argument("lpsz is nullptr");
}
if(nIndex < 0)
{
throw std::out_of_range("Insert position is negative");
}
if(nIndex > m_iLen)
{
throw std::out_of_range("Insert position is greater than the current length");
}
int lenInsert = strlen(lpsz);
// 分配新缓冲区
char* newBuf = new char[m_iLen + lenInsert + 1];
// 复制前半部分
memcpy(newBuf, m_pBuf, nIndex);
// 插入字符串
memcpy(newBuf + nIndex, lpsz, lenInsert);
// 复制后半部分
memcpy(newBuf + nIndex + lenInsert, m_pBuf + nIndex, m_iLen - nIndex);
// 终止字符串
newBuf[m_iLen + lenInsert] = '\0';
// 更新对象状态
delete[] m_pBuf;
m_pBuf = newBuf;
m_iLen += lenInsert;
return m_iLen;
}
// 删除指定位置开始的nCount个字符,返回剩余字符串长度
int CString::Delete(int nIndex, int nCount)
{
if(nIndex < 0 || nIndex >= m_iLen)
{
throw std::out_of_range("Delete position is out of range");
}
if(nCount <= 0)
{
throw std::invalid_argument("nCount should be greater than 0");
}
// 确保不越界
if(nIndex + nCount > m_iLen)
{
nCount = m_iLen - nIndex;
}
// 移动后面的字符覆盖删除部分
memmove(m_pBuf + nIndex, m_pBuf + nIndex + nCount, m_iLen - (nIndex + nCount) + 1);
// 更新长度
m_iLen -= nCount;
return m_iLen;
}
//在当前字符串中查找 lpszCharSet 中任意一个字符首次出现的位置
int CString::FindOneOf(const char* lpszCharSet) const
{
if(!lpszCharSet || !*lpszCharSet)
return -1; // 空字符集
for(int i = 0; i < m_iLen; i++)
{
for(const char* p = lpszCharSet; *p; p++)
{
if(m_pBuf[i] == *p)
{
return i; // 找到第一个匹配字符的位置
}
}
}
return -1; // 未找到任何匹配字符
}
bool operator!=(const char *str, const CString &Str)
{
if(str == nullptr)
return Str.m_iLen != 0;
return strlen(str) != Str.m_iLen || strncmp(str, Str.m_pBuf, Str.m_iLen) != 0;
}
bool operator< (const CString &Str, const char *str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return false; // 非空字符串不小于nullptr
}
// 使用strcmp比较两个字符串
return strcmp(Str.m_pBuf, str) < 0;
}
bool operator< (const char *str, const CString &Str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return Str.m_iLen > 0; // nullptr小于任何非空字符串
}
// 使用strcmp比较两个字符串
return strcmp(str, Str.m_pBuf) < 0;
}
bool operator> (const CString &Str, const char *str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return Str.m_iLen > 0; // 非空字符串大于nullptr
}
// 使用strcmp比较两个字符串
return strcmp(Str.m_pBuf, str) > 0;
}
bool operator<=(const CString &Str, const char *str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return Str.m_iLen == 0; // 仅空字符串<=nullptr
}
// 使用strcmp比较两个字符串
return strcmp(Str.m_pBuf, str) <= 0;
}
bool operator<=(const char *str, const CString &Str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return true; // nullptr小于等于任何字符串
}
// 使用strcmp比较两个字符串
return strcmp(str, Str.m_pBuf) <= 0;
}
bool operator> (const char *str, const CString &Str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return false; // nullptr不大于任何字符串
}
// 使用strcmp比较两个字符串
return strcmp(str, Str.m_pBuf) > 0;
}
// 比较CString对象是否大于等于字符串常量(按字典序)
bool operator>=(const CString &Str, const char *str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return true; // 任何字符串都大于等于nullptr
}
// 使用strcmp比较两个字符串
return strcmp(Str.m_pBuf, str) >= 0;
}
// 比较字符串常量是否大于等于CString对象(按字典序)
bool operator>=(const char *str, const CString &Str)
{
// 处理str为nullptr的情况:nullptr视为最小字符串
if(str == nullptr)
{
return Str.m_iLen == 0; // nullptr仅大于等于空字符串
}
// 使用strcmp比较两个字符串
return strcmp(str, Str.m_pBuf) >= 0;
}
int CString::Compare(const char *str) const
{
if(str == nullptr)
{
return m_iLen > 0 ? 1 : 0; // nullptr视为空字符串
}
return strcmp(m_pBuf, str);
}
int CString::Compare(const CString &Str) const
{
return strcmp(m_pBuf, Str.m_pBuf);
}
int CString::CompareNoCase(const char *str) const
{
if(str == nullptr)
{
return m_iLen > 0 ? 1 : 0; // nullptr视为空字符串
}
return strcasecmp(m_pBuf, str); // Windows: _stricmp, Linux: strcasecmp
}
int CString::CompareNoCase(const CString &Str) const
{
return strcasecmp(m_pBuf, Str.m_pBuf); // Windows: _stricmp, Linux: strcasecmp
}
测试代码
void testConstructors()
{
// 默认构造函数
CString s1;
assert(s1.GetLength() == 0);
assert(s1.IsEmpty());
// 从C风格字符串构造
CString s2("Hello");
assert(s2.GetLength() == 5);
assert(strcmp(s2.GetBuffer(0), "Hello") == 0);
// 从单个字符构造
CString s3('A');
assert(s3.GetLength() == 1);
assert(s3.GetAt(0) == 'A');
// 复制构造函数
CString s4(s2);
assert(s4.GetLength() == 5);
assert(strcmp(s4.GetBuffer(0), "Hello") == 0);
}
void testGetLengthAndIsEmpty()
{
CString s;
assert(s.GetLength() == 0);
assert(s.IsEmpty());
s = "Test";
assert(s.GetLength() == 4);
assert(!s.IsEmpty());
s.Empty();
assert(s.GetLength() == 0);
assert(s.IsEmpty());
}
void testElementAccess()
{
CString s("abc");
assert(s.GetAt(0) == 'a');
assert(s[1] == 'b');
s.SetAt(1, 'X');
assert(s[1] == 'X');
const CString cs("test");
assert(cs[2] == 's');
}
void testFindAndReverseFind()
{
CString s("Hello World");
assert(s.Find('o') == 4);
assert(s.Find('o', 5) == 7);
assert(s.Find("World") == 6);
assert(s.Find("xyz") == -1);
assert(s.ReverseFind('l') == 9);
assert(s.FindOneOf("aeiou") == 1);
assert(s.Find('d',10)==10);
}
void testModifyString()
{
CString s("Hello");
// Replace
assert(s.Replace('l', 'L') == 2);
assert(strcmp(s.GetBuffer(0), "HeLLo") == 0);
// Remove
assert(s.Remove('L') == 2);
assert(strcmp(s.GetBuffer(0), "Heo") == 0);
// Insert
assert(s.Insert(2, 'l') == 4);
assert(strcmp(s.GetBuffer(0), "Helo") == 0);
assert(s.Insert(3, "lo") == 6);
assert(strcmp(s.GetBuffer(0), "Helloo") == 0);
// Delete
assert(s.Delete(2, 3) == 3);
assert(strcmp(s.GetBuffer(0), "Heo") == 0);
}
void testAssignmentOperators()
{
CString s;
// 字符赋值
s = 'A';
assert(s.GetLength() == 1);
assert(s[0] == 'A');
// C风格字符串赋值
s = "Test";
assert(s.GetLength() == 4);
assert(strcmp(s.GetBuffer(0), "Test") == 0);
// CString赋值
CString s2("Copy");
s = s2;
assert(s.GetLength() == 4);
assert(strcmp(s.GetBuffer(0), "Copy") == 0);
}
void testAppendOperators()
{
CString s("Hello");
// 追加字符
s += ' ';
assert(strcmp(s.GetBuffer(0), "Hello ") == 0);
// 追加C风格字符串
s += "World";
assert(strcmp(s.GetBuffer(0), "Hello World") == 0);
// 追加CString
CString suffix("!");
s += suffix;
assert(strcmp(s.GetBuffer(0), "Hello World!") == 0);
}
void testFormat()
{
CString s;
s.Format("%d + %d = %d", 2, 3, 5);
assert(strcmp(s.GetBuffer(0), "2 + 3 = 5") == 0);
float value=1.234;
s.Format("%.2f",value);
assert(strcmp(s.GetBuffer(0), "1.23") == 0);
s.Format("%02x",55);
printf("s=%s\n",s.GetBuffer(0));
assert(strcmp(s.GetBuffer(0), "37") == 0);
}
void testSubstring()
{
CString s("HelloWorld");
assert(strcmp(s.Left(5).GetBuffer(0), "Hello") == 0);
assert(strcmp(s.Right(5).GetBuffer(0), "World") == 0);
assert(strcmp(s.Mid(5).GetBuffer(0), "World") == 0);
assert(strcmp(s.Mid(1, 3).GetBuffer(0), "ell") == 0);
}
void testCaseConversion()
{
CString s("Hello");
s.MakeUpper();
assert(strcmp(s.GetBuffer(0), "HELLO") == 0);
s.MakeLower();
assert(strcmp(s.GetBuffer(0), "hello") == 0);
}
void testTrim()
{
CString s(" \tHello World! \n");
CString s2(" ");
s2.Trim();
assert(s2.IsEmpty());
s.TrimLeft();
assert(strcmp(s.GetBuffer(0), "Hello World! \n") == 0);
s.TrimRight();
assert(strcmp(s.GetBuffer(0), "Hello World!") == 0);
s = " \t Test \t ";
s.Trim();
assert(strcmp(s.GetBuffer(0), "Test") == 0);
}
void testReverse()
{
CString s("abc");
s.MakeReverse();
assert(strcmp(s.GetBuffer(0), "cba") == 0);
}
void testConcatenation()
{
CString s1("Hello");
CString s2(" World");
CString s3 = s1 + s2;
assert(strcmp(s3.GetBuffer(0), "Hello World") == 0);
CString s4 = s1 + '!';
assert(strcmp(s4.GetBuffer(0), "Hello!") == 0);
CString s5 = "Hi" + s1;
assert(strcmp(s5.GetBuffer(0), "HiHello") == 0);
CString s6 = 'A' + s1;
assert(strcmp(s6.GetBuffer(0), "AHello") == 0);
}
void testComparisonOperators()
{
CString s1("abc");
CString s2("abc");
CString s3("abd");
// ==
assert(s1 == s2);
assert(s1 == "abc");
assert("abc" == s1);
// !=
assert(s1 != s3);
assert(s1 != "abd");
assert("abd" != s1);
// >
assert(s3 > s1);
assert(s3 > "abc");
assert("abd" > s1);
// >=
assert(s1 >= s2);
assert(s3 >= s1);
assert(s1 >= "abc");
assert("abd" >= s1);
// <
assert(s1 < s3);
assert(s1 < "abd");
assert("abc" < s3);
// <=
assert(s1 <= s2);
assert(s1 <= s3);
assert(s1 <= "abd");
assert("abc" <= s3);
}
void testCompare()
{
CString s1("Hello");
CString s2("hello");
int r1 = s1.Compare("Hello"); // 0
assert(r1==0);
int r2 = s1.Compare("World"); // <0
assert(r2<0);
int r3 = s1.CompareNoCase("HELLO"); // 0
assert(r3==0);
int r4 = s1.Compare(s2); // <0 (大小写敏感)
assert(r4<0);
int r5 = s1.CompareNoCase(s2); // 0 (大小写不敏感)
assert(r5==0);
}