自定义CString类与MFC CString类接口对比

接口对比表格

|----------------|-----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------|
| 功能分类 | 你的 CString 接口 | MFC CString 接口(ANSI) | 一致性 | 差异说明 |
| 构造函数 | CString() CString(const char*) CString(char) CString(const CString&) | CString() CString(LPCSTR) CString(TCHAR) CString(const CString&) | 一致 | MFC 使用 LPCSTR(const char*),命名和参数逻辑相同。 |
| 析构函数 | ~CString() | ~CString() | 一致 | 均需手动释放内存(MFC 内部自动管理 COW 缓冲区)。 |
| 长度与判空 | int GetLength() const bool IsEmpty() const void Empty() | int GetLength() const BOOL IsEmpty() const void Empty() | 一致 | MFC 返回 BOOL(等效 bool),功能相同。 |
| 字符访问 | char GetAt(int) const char& operator[] const char& operator[] const | TCHAR GetAt(int) const TCHAR& operator[] const TCHAR& operator[] const | 一致 | MFC 使用 TCHAR(char in ANSI),越界处理:MFC 断言,你抛出异常。 |
| 修改字符 | void SetAt(int, char) | void SetAt(int, TCHAR) | 一致 | 参数和逻辑相同。 |
| 查找操作 | int Find(char) const int Find(const char*) const int ReverseFind(char) const int FindOneOf(const char*) const | int Find(TCHAR) const int Find(LPCTSTR) const int ReverseFind(TCHAR) const int FindOneOf(LPCTSTR) const | 一致 | MFC 参数为 LPCTSTR(const char*),功能相同。 |
| 替换操作 | int Replace(char, char) int Replace(const char*, const char*) | int Replace(TCHAR, TCHAR) int Replace(LPCTSTR, LPCTSTR) | 一致 | 均返回替换次数,字符串替换需动态扩容。 |
| 删除操作 | int Remove(char) | int Remove(TCHAR) | 一致 | 均返回删除次数,逻辑相同。 |
| 插入操作 | int Insert(int, char) int Insert(int, char*) | int Insert(int, TCHAR) int Insert(int, LPCTSTR) | 一致 | 参数和返回值(新长度)相同,MFC 支持 CString 插入(通过 LPCTSTR 兼容)。 |
| 删除子串 | int Delete(int, int = 1) | int Delete(int, int = 1) | 一致 | 默认删除 1 个字符,越界处理逻辑需确保安全。 |
| 子串操作 | CString Left(int) const CString Right(int) const CString Mid(int) const CString Mid(int, int) const | CString Left(int) const CString Right(int) const CString Mid(int) const CString Mid(int, int) const | 一致 | 均返回子串对象,处理越界时返回空串。 |
| 赋值运算符 | CString& operator=(char) CString& operator=(const char*) CString& operator=(const CString&) | CString& operator=(TCHAR) CString& operator=(LPCTSTR) CString& operator=(const CString&) | 一致 | MFC 无非常量引用赋值,你已删除 operator=(CString&),与 MFC 一致。 |
| 追加运算符 | CString& operator+=(char) CString& operator+=(const char*) CString& operator+=(const CString&) | CString& operator+=(TCHAR) CString& operator+=(LPCTSTR) CString& operator+=(const CString&) | 一致 | 功能相同,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 MakeLower() | void MakeUpper() void MakeLower() | 部分一致 | MFC 支持本地化转换(如土耳其语),你仅实现 ASCII 转换。 |
| 去除空白字符 | void TrimLeft() void TrimRight() void Trim() | void TrimLeft() void TrimRight() void Trim() | 部分一致 | MFC 默认识别所有空白字符(如制表符),你的实现依赖 isspace(一致)。 |
| 反转字符串 | CString& MakeReverse() | CStringT& MakeReverse() | 一致 | MFC 通过 StringTraits::StringReverse 实现,你通过手动交换字符实现,功能相同。 |
| 内存管理接口 | char* GetBuffer(int) | LPTSTR GetBuffer(int) void ReleaseBuffer() | 差异 | 你未提供 ReleaseBuffer(),需手动管理长度;MFC 通过 ReleaseBuffer() 自动更新。 |
| 高级功能 | 无 Tokenize/LoadString/ 路径处理等 | 支持 Tokenize/LoadString/ExtractFilePath 等 | 缺失 | MFC 提供字符串分词、资源加载、路径解析等高级功能。 |
| 安全检查 | 部分函数抛出异常(如越界) | 部分函数内部断言(如 ATLASSERT) | 差异 | MFC 依赖调试断言,你使用异常处理,均实现基本安全控制。 |

关键结论

1.基础操作完全一致

构造 / 析构、查找 / 替换、比较 / 连接等核心接口的命名、参数和功能与 MFC 一致,可直接映射。

2.const 修饰完全对齐

所有 const 成员函数、参数均符合 MFC 规范,类型安全无差异。

差异与缺失

  1. 内存管理 :缺少 ReleaseBuffer(),需手动处理 GetBuffer() 后的长度更新。
  2. 高级功能 :无 Tokenize、资源加载、路径处理等 MFC 特有功能。
  3. 本地化 :大小写转换未考虑区域设置,MFC 支持更全面。

适用场景

  1. 一致场景 :ANSI 环境下的基础字符串操作,如简单文本处理、非国际化逻辑。
  2. 不一致场景 :需要 Unicode、高性能内存管理(COW)、复杂字符串处理(如路径解析)的场景。

cstring.h

cpp 复制代码
#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

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
}

测试代码

cpp 复制代码
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);
}
相关推荐
顾子茵15 分钟前
c++从入门到精通(五)--异常处理,命名空间,多继承与虚继承
开发语言·c++
humors2211 小时前
Windows运维工具批处理版
运维·windows·计算机·电脑·笔记本·维护·台式机
TNTLWT1 小时前
Qt控件:交互控件
开发语言·qt
YueiL2 小时前
基于RK3588的智慧农场系统开发|RS485总线|华为云IOT|node-red|MQTT
c++·物联网·华为云·rk3588·rs485
二进制人工智能2 小时前
【OpenGL学习】(二)OpenGL渲染简单图形
c++·opengl
hnlucky2 小时前
Windows 上安装下载并配置 Apache Maven
java·hadoop·windows·学习·maven·apache
Dream it possible!2 小时前
LeetCode 热题 100_寻找重复数(100_287_中等_C++)(技巧)(暴力解法;哈希集合;二分查找)
c++·leetcode·哈希算法
洛阳泰山3 小时前
Windows系统部署MongoDB数据库图文教程
数据库·windows·mongodb
丶Darling.3 小时前
Day119 | 灵神 | 二叉树 | 二叉树的最近共公共祖先
数据结构·c++·算法·二叉树
阿斯顿法国红酒快4 小时前
Windows系统安全加固
网络·windows·安全·网络安全·系统安全·ddos