CString-clone 使用标准 C++






4.93/5 (122投票s)
CString 的直接替换方案,基于标准 C++ 库的 basic_string 模板
引言
尽管我经常使用并欣赏标准 C++ 库,但我一直不喜欢它的字符串模板 - basic_string<>
。有时,感觉设计者刻意使其难以使用。
另一方面,我一直很喜欢 MFC 的 CString
类的易用性。它会检查 NULL 指针,隐式转换为 const TCHAR*
,并且拥有一些非常方便的成员函数(Format
、Load
等),让字符串编程变得轻而易举。但当然,我不想再使用 MFC 了。事实上,我也不想依赖任何专有库,因为我想要可移植性。
因此,我决定结合两者的优点,创造了
CStdString
这是一个类(实际上是模板实例化),它继承自 basic_string<TCHAR>
。它为 basic_string
添加了完整的 CString
API。你将获得 CString
的易用性,同时具有 100% 的 basic_string
兼容性。简而言之,CStdString
对象是一个 basic_string
,它(除了下面提到的极少数例外)同时也是 CString
的直接替换方案。最棒的是,这两个 API(basic_string
和 CString
)都广为人知且文档齐全。
几年前,我最初将这篇文章提交给了另一个代码网站(此处不具名 :))。我非常喜欢 CodeProject,所以也想在这里提交。在过去 4 年里,我几乎在我做的每一个专业项目中都使用了这个类。它证明是我写过的最有用的代码。它也经过了广泛的调试。希望你喜欢它。如果你有任何问题,请给我发电子邮件。我很乐意提供帮助。
我在此提供了一个简单的源应用程序来证明一些 CString
函数可以正常工作,但这只是象征性的。目前市面上使用 CString
和/或 basic_string
的示例项目数不胜数。
特点
- CString 的直接替换方案(例外情况请参见下文)
- 随时提供两个实例化 -
wchar_t
-based 版本CStdStringW
和char
-based 版本CStdStringA
。CStdString
这个名字只是其中一个的typedef
。 - 在所有函数中安全地检查
NULL 字符串
指针输入(类似于CString
) - 额外的构造函数和赋值运算符,可自动在宽(
wchar_t
-based)和窄(char
-based)string
之间进行转换。 - 隐式转换为
c_str()
。C++ 标准委员会不喜欢这样,但我很喜欢。 - 可在多个平台构建,包括 Windows、Unix 和 Linux。可与多种标准 C++ 库实现配合使用,包括 Dinkumware、GNU、CodeWarrior 和 STLPort。
- Win32 构建提供了一些额外的功能,如 UNICODE/MBCS 转换宏(类似于 MFC)以及用于将
CStdString
对象持久化到 DCOMIStream
s 和从 DCOMIStream
s 中恢复的成员函数。 - 不使用基类模板(
basic_string
)的任何实现细节 - 派生模板不向
basic_string
添加任何成员数据,也不添加虚函数
关于这段代码,有几个问题我应该指出。
CString 兼容性
我未能完全重现 CString
API。有两个函数 CString
和 basic_string
都共享,但实现方式不同。在这些情况下,我认为最好让 CStdString
的行为类似于 basic_string
(基类),而不是 CString
。具体来说:
CStdString::operator[]
按值返回字符(与按引用返回字符的CString
不同)- 以字符和计数为参数的构造函数,它们的顺序是(
count
,value
),这与CString
的声明顺序相反。这是basic_string<>
所需的顺序,无法同时实现两个版本。
另外,还有两个 CString
函数我无法实现 - LockBuffer
和 UnlockBuffer
。
从 basic_string<> 派生
我编写的模板继承自 basic_string
,这是一个没有虚析构函数的类模板。任何 C++ 入门教程都会告诉你,从没有虚析构函数的类派生是危险的。这可能导致未定义行为。所以如果你编写了以下代码(通过基类指针删除 CStdStringA
),你将技术上得到未定义行为
// assign DERIVED object to BASE pointer
std::string* pstr = new CStdStringA("Hi");
// delete DERIVED through BASE class pointer -- UNDEFINED
delete pstr;
我个人认为这不是什么大问题。我是说,你多久真正对 string
对象这样做一次?我很少(甚至从不)需要在堆上动态分配 string
对象。如果我需要,我也不会使用基类指针。所以如果你不这样做,你就不必担心。事实上,即使你以这种方式编码,我也怀疑 CStdString
会给你带来任何问题。我可以告诉你,至少在 Microsoft Visual C++ 中,即使是上面的代码也能正常运行,没有任何错误或内存泄漏。我怀疑其他编译器也会给你带来麻烦。然而,我的怀疑并不能改变 C++ 世界的现实。买者自负。
历史
- 2011 年 12 月 7 日:更新了源代码。