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

发布于:2025-05-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

接口对比表格

功能分类

你的 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

#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);
}


网站公告

今日签到

点亮在社区的每一天
去签到