分享一个安全的CString

本 CString 类是基于 C++ 标准库std::string封装的轻量级字符串工具类,兼容常用字符串操作需求,无需手动管理内存,安全稳定。类提供完整的构造、赋值、拼接、比较、截取、查找、格式化等功能,包含GetAt、[]运算符重载,支持读写访问;实现Left/Right/Mid截取、Trim去空格、大小写转换、Format格式化等实用接口。所有接口做了越界、空指针等安全校验,避免程序崩溃,整体简洁易用、鲁棒性强,适用于日常字符串处理场景。

先上测试用例:

#include "CString.h"

#include <cstdio>

// 修复后的宏定义

#define TEST_CASE(str) printf("\n=== 测试: %s ===\n", str);

#define CHECK(a) printf("结果: %s\n", a);

int main()

{

//=========================

// 1. 构造函数测试

//=========================

TEST_CASE("构造函数");

CString s1;

CString s2("hello");

CString s3('A');

CString s4(s2);

CHECK(s1.GetBuffer(0));

CHECK(s2.GetBuffer(0));

CHECK(s3.GetBuffer(0));

CHECK(s4.GetBuffer(0));

//=========================

// 2. 基础属性

//=========================

TEST_CASE("基础属性");

char buf[64];

sprintf(buf, "长度: %d", s2.GetLength());

CHECK(buf);

sprintf(buf, "是否空: %s", s1.IsEmpty() ? "是" : "否");

CHECK(buf);

s1.Empty();

sprintf(buf, "清空后是否空: %s", s1.IsEmpty() ? "是" : "否");

CHECK(buf);

//=========================

// 3. 字符访问 GetAt / []

//=========================

TEST_CASE("字符访问");

CString s5("test123");

sprintf(buf, "%c", s5.GetAt(0));

CHECK(buf);

sprintf(buf, "%c", s5[1]);

CHECK(buf);

s5[0] = 'T';

CHECK(s5.GetBuffer(0));

//=========================

// 4. 赋值 =

//=========================

TEST_CASE("赋值");

CString s6;

s6 = "assign test";

CHECK(s6.GetBuffer(0));

s6 = 'X';

CHECK(s6.GetBuffer(0));

s6 = s5;

CHECK(s6.GetBuffer(0));

//=========================

// 5. 拼接 +=

//=========================

TEST_CASE("+=");

CString s7("abc");

s7 += "123";

s7 += '4';

s7 += CString("567");

CHECK(s7.GetBuffer(0));

//=========================

// 6. 截取 Left / Right / Mid

//=========================

TEST_CASE("Left / Right / Mid");

CString s8("123456789");

CHECK(s8.Left(3).GetBuffer(0));

CHECK(s8.Right(3).GetBuffer(0));

CHECK(s8.Mid(2).GetBuffer(0));

CHECK(s8.Mid(2, 4).GetBuffer(0));

//=========================

// 7. 查找 Find

//=========================

TEST_CASE("Find");

CString s9("abc123abc456");

sprintf(buf, "查找字符: %d", s9.Find('c'));

CHECK(buf);

sprintf(buf, "查找串: %d", s9.Find("123"));

CHECK(buf);

sprintf(buf, "从位置5查找: %d", s9.Find("abc", 5));

CHECK(buf);

sprintf(buf, "查找CString: %d", s9.Find(CString("456")));

CHECK(buf);

sprintf(buf, "查找CString: %d", s9.Find(CString("xx")));

CHECK(buf);

//=========================

// 8. Trim 系列

//=========================

TEST_CASE("Trim");

CString s10(" abc def \r\n");

s10.TrimLeft();

s10.TrimRight();

sprintf(buf, "TrimLeft+Right: %s", s10.GetBuffer(0));

CHECK(buf);

CString s11(" xyz ");

s11.Trim();

sprintf(buf, "Trim: %s", s11.GetBuffer(0));

CHECK(buf);

//=========================

// 9. 大小写 MakeLower / MakeUpper

//=========================

TEST_CASE("大小写");

CString s12("AbCdEfG");

s12.MakeUpper();

sprintf(buf, "大写: %s", s12.GetBuffer(0));

CHECK(buf);

s12.MakeLower();

sprintf(buf, "小写: %s", s12.GetBuffer(0));

CHECK(buf);

//=========================

// 10. GetBuffer

//=========================

TEST_CASE("GetBuffer");

CString s13("buffer test");

const char* pConst = s13.GetBuffer(0);

char* pNoConst = s13.GetBuffer(0);

CHECK(pConst);

CHECK(pNoConst);

//=========================

// 11. Format

//=========================

TEST_CASE("Format");

CString s14;

s14.Format("编号:%d,内容:%s", 100, "test string");

CHECK(s14.GetBuffer(0));

//=========================

// 12. 比较 == != > < >= <=

//=========================

TEST_CASE("比较运算符");

CString a("aaa"), b("bbb");

sprintf(buf, "==: %d", a == b);

CHECK(buf);

sprintf(buf, "!=: %d", a != b);

CHECK(buf);

sprintf(buf, "> : %d", a > b);

CHECK(buf);

sprintf(buf, "< : %d", a < b);

CHECK(buf);

sprintf(buf, ">=: %d", a >= b);

CHECK(buf);

sprintf(buf, "<=: %d", a <= b);

CHECK(buf);

sprintf(buf, "== const char*: %d", a == "aaa");

CHECK(buf);

//=========================

// 13. 全局 + 运算符

//=========================

TEST_CASE("+ 拼接");

CString x("111"), y("222");

CString r1 = x + y;

CString r2 = x + "333";

CString r3 = "444" + y;

CString r4 = x + '5';

CHECK(r1.GetBuffer(0));

CHECK(r2.GetBuffer(0));

CHECK(r3.GetBuffer(0));

CHECK(r4.GetBuffer(0));

printf("\n==== 所有函数测试完成 ====\n");

return 0;

}

测试结果:

=== 测试: 构造函数 ===

结果:

结果: hello

结果: A

结果: hello

=== 测试: 基础属性 ===

结果: 长度: 5

结果: 是否空: 是

结果: 清空后是否空: 是

=== 测试: 字符访问 ===

结果: t

结果: e

结果: Test123

=== 测试: 赋值 ===

结果: assign test

结果: X

结果: Test123

=== 测试: += ===

结果: abc1234567

=== 测试: Left / Right / Mid ===

结果: 123

结果: 789

结果: 3456789

结果: 3456

=== 测试: Find ===

结果: 查找字符: 2

结果: 查找串: 3

结果: 从位置5查找: 6

结果: 查找CString: 9

结果: 查找CString: -1

=== 测试: Trim ===

结果: TrimLeft+Right: abc def

结果: Trim: xyz

=== 测试: 大小写 ===

结果: 大写: ABCDEFG

结果: 小写: abcdefg

=== 测试: GetBuffer ===

结果: buffer test

结果: buffer test

=== 测试: Format ===

结果: 编号:100,内容:test string

=== 测试: 比较运算符 ===

结果: ==: 0

结果: !=: 1

结果: > : 0

结果: < : 1

结果: >=: 0

结果: <=: 1

结果: == const char*: 1

=== 测试: + 拼接 ===

结果: 111222

结果: 111333

结果: 444222

结果: 1115

==== 所有函数测试完成 ====

CString.h

cpp 复制代码
#ifndef CSTRING_H
#define CSTRING_H

#include <string>

// 字符串封装类(模拟MFC CString)
class CString
{
private:
    std::string m_str;  // 内部存储字符串的成员变量

public:
    // 构造与析构
    CString();                   // 默认构造(空字符串)
    CString(const CString& str); // 拷贝构造
    CString(const char* lpsz);   // 从C字符串构造
    CString(char ch);            // 从单个字符构造
    ~CString();                  // 析构函数

    // 基础属性操作
    int GetLength() const;   // 获取字符串长度
    bool IsEmpty() const;    // 判断是否为空
    void Empty();            // 清空字符串

    // 字符访问
    char GetAt(int iIndex) const;        // 获取指定位置字符(带检查)
    char operator[](int iIndex) const;   // 只读下标访问
    char& operator[](int iIndex);        // 可写下标访问

    // 赋值运算符
    CString& operator=(const CString& str);
    CString& operator=(const char* lpsz);
    CString& operator=(char ch);

    // 追加运算符
    CString& operator+=(const CString& str);
    CString& operator+=(const char* lpsz);
    CString& operator+=(char ch);

    // 字符串截取
    CString Left(int nCount) const;     // 取左侧n个字符
    CString Right(int nCount) const;    // 取右侧n个字符
    CString Mid(int nFirst) const;      // 从n开始取到末尾
    CString Mid(int nFirst, int nCount) const; // 从n取count个字符

    // 查找函数
    int Find(char ch) const;                  // 查找字符
    int Find(const char* lpszSub) const;      // 查找子串
    int Find(const char* lpszSub, int nStart) const; // 从指定位置查找
    int Find(const CString& strSub) const;    // 查找CString子串

    // 修剪空白
    void TrimLeft();    // 去除左侧空白
    void TrimRight();   // 去除右侧空白
    void Trim();        // 去除左右空白

    // 大小写转换
    void MakeLower();   // 转为小写
    void MakeUpper();   // 转为大写

    // 缓冲区操作
    char* GetBuffer(int = 0);                // 获取可写缓冲区
    const char* GetBuffer(int = 0) const;    // 获取只读缓冲区
    void Format(const char* pstrFormat, ...); // 格式化字符串

    // 比较运算符(CString)
    bool operator==(const CString& str) const;
    bool operator!=(const CString& str) const;
    bool operator>(const CString& str) const;
    bool operator<(const CString& str) const;
    bool operator>=(const CString& str) const;
    bool operator<=(const CString& str) const;

    // 比较运算符(C字符串)
    bool operator==(const char* lpsz) const;
    bool operator!=(const char* lpsz) const;
    bool operator>(const char* lpsz) const;
    bool operator<(const char* lpsz) const;
    bool operator>=(const char* lpsz) const;
    bool operator<=(const char* lpsz) const;

    // 友元拼接运算符
    friend CString operator+(const CString& s1, const CString& s2);
    friend CString operator+(const CString& s1, const char* s2);
    friend CString operator+(const char* s1, const CString& s2);
    friend CString operator+(const CString& s1, char ch);
};

#endif

CString.cpp

cpp 复制代码
/*
本 CString 类是基于 C++ 标准库std::string封装的轻量级字符串工具类,兼容常用字符串操作需求,1
无需手动管理内存,安全稳定。类提供完整的构造、赋值、拼接、比较、截取、查找、格式化等功能,包含GetAt、
[]运算符重载,支持读写访问;实现Left/Right/Mid截取、Trim去空格、大小写转换、Format格式化等实用接口。
所有接口做了越界、空指针等安全校验,避免程序崩溃,整体简洁易用、鲁棒性强,适用于日常字符串处理场景。
*/
#include "CString.h"
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <cctype>
#include <memory>
#include <stdexcept>   // 加这个!

// 默认构造:空字符串
CString::CString()
{
}

// 拷贝构造
CString::CString(const CString& str)
{
    m_str = str.m_str;
}

// 从 C 字符串构造
CString::CString(const char* lpsz)
{
    if(lpsz)
        m_str = lpsz;
}

// 从单个字符构造
CString::CString(char ch)
{
    m_str = ch;
}

// 析构函数
CString::~CString()
{
}

// 获取字符串长度
int CString::GetLength() const
{
    return (int)m_str.size();
}

// 判断是否为空
bool CString::IsEmpty() const
{
    return m_str.empty();
}

// 清空字符串
void CString::Empty()
{
    m_str.clear();
}

// 获取指定位置字符
char CString::GetAt(int iIndex) const
{
    if(iIndex < 0 || iIndex >= GetLength())
        return 0;
    return m_str[iIndex];
}

// 只读下标访问
char CString::operator[](int iIndex) const
{
    return GetAt(iIndex);
}


// 可写下标访问
char& CString::operator[](int iIndex)
{
    if (iIndex < 0 || iIndex >= GetLength())
    {
        throw std::out_of_range("CString[] index out of range");
    }
    return m_str[iIndex];
}

// 赋值运算符(CString)
CString& CString::operator=(const CString& str)
{
    m_str = str.m_str;
    return *this;
}

// 赋值运算符(C字符串)
CString& CString::operator=(const char* lpsz)
{
    if(lpsz)
        m_str = lpsz;
    else
        m_str.clear();
    return *this;
}

// 赋值运算符(单个字符)
CString& CString::operator=(char ch)
{
    m_str = ch;
    return *this;
}

// 追加字符串(CString)
CString& CString::operator+=(const CString& str)
{
    m_str += str.m_str;
    return *this;
}

// 追加字符串(C字符串)
CString& CString::operator+=(const char* lpsz)
{
    if(lpsz)
        m_str += lpsz;
    return *this;
}

// 追加单个字符
CString& CString::operator+=(char ch)
{
    m_str += ch;
    return *this;
}

// 取左边nCount个字符
CString CString::Left(int nCount) const
{
    if(nCount <= 0)
        return CString();
    if(nCount > GetLength())
        nCount = GetLength();
    return CString(m_str.substr(0, nCount).c_str());
}

// 取右边nCount个字符
CString CString::Right(int nCount) const
{
    int len = GetLength();
    if(nCount <= 0 || len == 0)
        return CString();
    if(nCount > len)
        nCount = len;
    return CString(m_str.substr(len - nCount, nCount).c_str());
}

// 从nFirst取到末尾
CString CString::Mid(int nFirst) const
{
    int len = GetLength();
    if(nFirst < 0 || nFirst >= len)
        return CString();
    return CString(m_str.substr(nFirst).c_str());
}

// 从nFirst取nCount个字符
CString CString::Mid(int nFirst, int nCount) const
{
    int len = GetLength();
    if(nFirst < 0 || nCount <= 0 || nFirst >= len)
        return CString();
    if(nFirst + nCount > len)
        nCount = len - nFirst;
    return CString(m_str.substr(nFirst, nCount).c_str());
}

// 查找单个字符
int CString::Find(char ch) const
{
    size_t pos = m_str.find(ch);
    if(pos == std::string::npos)
        return -1;
    return (int)pos;
}

// 查找子串(C字符串)
int CString::Find(const char* lpszSub) const
{
    if(!lpszSub || *lpszSub == 0)
        return -1;
    size_t pos = m_str.find(lpszSub);
    if(pos == std::string::npos)
        return -1;
    return (int)pos;
}
// 从指定位置查找子串(C字符串)
int CString::Find(const char* lpszSub, int nStart) const
{
    if(!lpszSub) return -1;
    if(*lpszSub == 0) return 0;
    if(nStart < 0 || nStart >= GetLength())
        return -1;

    size_t pos = m_str.find(lpszSub, nStart);
    if(pos == std::string::npos)
        return -1;

    return (int)pos;
}

// 查找子串(CString)
int CString::Find(const CString& strSub) const
{
    return Find(strSub.GetBuffer(0));
}

// 获取缓冲区
char* CString::GetBuffer(int)
{
    return (char*)m_str.c_str();
}

// 获取只读缓冲区
const char* CString::GetBuffer(int) const
{
    return m_str.c_str();
}

void CString::Format(const char* pstrFormat, ...)
{
    if (pstrFormat == nullptr)
    {
        m_str.clear();
        return;
    }

    va_list argList;
    va_start(argList, pstrFormat);

    // 1. 先复制一份用来计算长度
    va_list argsCopy;
    va_copy(argsCopy, argList);
    int len = vsnprintf(nullptr, 0, pstrFormat, argsCopy);
    va_end(argsCopy);

    if (len < 0) {
        va_end(argList);  // 这里必须结束主列表
        m_str.clear();
        return;
    }

    // 2. 再复制一份用来真正输出
    std::unique_ptr<char[]> buf(new char[len + 1]);

    va_copy(argsCopy, argList);  // ✅ 重新复制
    vsnprintf(buf.get(), len + 1, pstrFormat, argsCopy);
    va_end(argsCopy);

    // 最后结束主列表
    va_end(argList);

    m_str = buf.get();
}

// 相等比较
bool CString::operator==(const CString& str) const
{
    return m_str == str.m_str;
}

// 不等比较
bool CString::operator!=(const CString& str) const
{
    return m_str != str.m_str;
}

// 与C字符串相等比较
bool CString::operator==(const char* lpsz) const
{
    if(!lpsz)
        return IsEmpty();
    return m_str == lpsz;
}

// 与C字符串不等比较
bool CString::operator!=(const char* lpsz) const
{
    return !(*this == lpsz);
}

// 字符串拼接(CString + CString)
CString operator+(const CString& s1, const CString& s2)
{
    CString s;
    s.m_str = s1.m_str + s2.m_str;
    return s;
}

// 字符串拼接(CString + C字符串)
CString operator+(const CString& s1, const char* s2)
{
    CString s;
    if(s2)
    {
        s.m_str = s1.m_str + s2;
    }
    else
    {
        s.m_str = s1.m_str;
    }
    return s;
}

// 字符串拼接(C字符串 + CString)
CString operator+(const char* s1, const CString& s2)
{
    CString s;
    if(s1)
    {
        s.m_str = s1 + s2.m_str;
    }
    else
    {
        s.m_str = s2.m_str;
    }
    return s;
}

// 字符串拼接(CString + 字符)
CString operator+(const CString& s1, char ch)
{
    CString s;
    s.m_str = s1.m_str + ch;
    return s;
}

// 去除左侧空白
void CString::TrimLeft()
{
    size_t start = m_str.find_first_not_of(" \t\n\r");
    if(start == std::string::npos)
        m_str.clear();
    else
        m_str = m_str.substr(start);
}

// 去除右侧空白
void CString::TrimRight()
{
    size_t end = m_str.find_last_not_of(" \t\n\r");
    if(end == std::string::npos)
        m_str.clear();
    else
        m_str.erase(end + 1);
}
// 去除左右空白
void CString::Trim()
{
    TrimLeft();
    TrimRight();
}

// 转小写
void CString::MakeLower()
{
    int len = GetLength();
    for (int i = 0; i < len; i++)
    {
        m_str[i] = tolower(m_str[i]);
    }
}

// 转大写
void CString::MakeUpper()
{
    int len = GetLength();
    for (int i = 0; i < len; i++)
    {
        m_str[i] = toupper(m_str[i]);
    }
}

// 大于比较(CString)
bool CString::operator>(const CString& str) const
{
    return m_str > str.m_str;
}

// 小于比较(CString)
bool CString::operator<(const CString& str) const
{
    return m_str < str.m_str;
}

// 大于等于(CString)
bool CString::operator>=(const CString& str) const
{
    return m_str >= str.m_str;
}

// 小于等于(CString)
bool CString::operator<=(const CString& str) const
{
    return m_str <= str.m_str;
}


// 大于比较(C字符串)
bool CString::operator>(const char* lpsz) const
{
    if(!lpsz)
        return !IsEmpty();
    return m_str > lpsz;
}

// 小于比较(C字符串)
bool CString::operator<(const char* lpsz) const
{
    if(!lpsz)
        return false;
    return m_str < lpsz;
}

// 大于等于(C字符串)
bool CString::operator>=(const char* lpsz) const
{
    if(!lpsz)
        return !IsEmpty();
    return m_str >= lpsz;
}

// 小于等于(C字符串)
bool CString::operator<=(const char* lpsz) const
{
    if(!lpsz)
        return false;
    return m_str <= lpsz;
}
相关推荐
桦02 小时前
[C++复习]:STL
开发语言·c++
木心术13 小时前
OpenClaw主动反爬虫机制安全配置指南
爬虫·安全
淼淼爱喝水3 小时前
openEuler 下 Ansible 基础命令详解与实操演示2
linux·运维·windows
风途_说气象水文3 小时前
大坝安全监测站:守护水利安全~
其他·安全
One_Blanks3 小时前
WIndows ShellCode开发 第四章 动态API调用
windows·网络安全·渗透测试
小陈工3 小时前
2026年3月31日技术资讯洞察:AI智能体安全、异步编程突破与Python运行时演进
开发语言·jvm·数据库·人工智能·python·安全·oracle
爱编码的小八嘎3 小时前
C语言完美演绎6-2
c语言
苏宸啊3 小时前
rbtree封装map和set
c++
idolao3 小时前
RStudio 2025 + R 4.5.0 安装与配置教程 Windows版:解压+双软件安装+自定义路径+R语言关联指南
windows