65.9K
CodeProject 正在变化。 阅读更多。
Home

CString 和 std::string 集成

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (11投票s)

2019年9月29日

MIT

5分钟阅读

viewsIcon

19672

downloadIcon

408

仅 CString 项目可以转换为 STL std::string。

引言

在 MFC 编程了几十年后,我开始的许多新项目仅仅因为我太习惯于 CString 类。甚至到了我将 MFC 集成到那些项目中只是为了使用 CString 类的地步。几次试图完全摆脱 MFC 的尝试都失败了。不是因为 std::string 不是一个好的 string 类,而是因为熟悉了前一个 string 类所有的方法。此外,CString 知道一些你偶尔需要的绝活,比如获取 BSTR 字符串、获取环境变量,或者像‘FormatV’这样的各种技巧,而这些你需要一个额外的函数。所以在算法进行到一半的时候,我就会卡住,试图回忆‘这个字符串类如何做这件事’。这会打断我的思路。这种在某个字符串操作上的来回折腾经常会导致对当前工作的分心。

一个解决方案:更努力地学习

当然,一个解决方案是更努力地学习 std::string。但知识不是唯一的解决方案。字面上讲,有数百万行代码堆在那里。不仅在我的私人项目中,也在办公室里。在工作中,我们需要支持数百万行包含 MFC CString 的代码。所以我总是押宝在两匹马上,并试图不把它们混淆。

另一个解决方案:消除

另一个可能性显然是消除其中一个类。最好是旧的那个(MFC CString)得走。你没有理由不能将 std::string 添加到一个混合了其他类的源代码库中。而且我已经在大量使用 STL 容器,比如‘vector’、‘set’、‘map’和‘multimap’,而不是使用旧的 MFC 容器。但即便如此:这将是一项艰巨的工作,而且没有额外的功能与之附加。

我的解决方案:集成

这里选择的道路是集成这两个类。从 std::string 派生出一个新类,这样新类就拥有了 STL 标准 string 类所有的标准功能。然后,将所有 MFC CString 的方法添加到这个类中。这样我们就可以同时拥有两者。

现在我听到你在想:“恶心!”这真是件可怕的事!

是的。我知道!最终结果不是一个漂亮而全面的类。但请等等…… 赢在其中的部分不是这个最终结果。赢在其中的部分是你编程时不想停止正在做的事情。所有你曾经需要记住的东西现在都封装在这个新的 string 类中。

另一个优势是你可以将其作为即插即用替换。

新类名为“SMX_String”,代表“Standard MFC eXtended String”。“SMX_String.h”文件中的接口定义以选择的名称重写结尾。在这里,我们选择了一个更漂亮的名称来进行编程。第一种情况是简单的“String”,由一个 typdef 定义。

万一我们手头的项目只有一个 CString,我们可以用 typedefCString 重命名为我们的新类。我们甚至可以用宏重命名一个“std::string”(但这不好)。

// Now typedef this as a standard "String"
typedef SMX_String String;

// Use this typedef for a plugin-replacement of a MFC CString-only project
// typedef SMX_String CString;

// Use this in a std::string based project to override the standard string
// #define string SMX_String

最终结果:两种方法集都可访问

这样你就拥有了。你现在可以拥有一个不含 MFC 的项目,并且拥有一个 string 类,它可以在一个包中同时完成 std::stringMFC::CString 的功能。

现在我们可以用“String”做任何我们想做的事情。在上面的例子中,你可以看到你可以同时使用“c_str()”和“GetString()”,并且“Left(n)”也起作用。无需去检查数百万行代码来消除所有那些“Left()”。😊

未起作用的部分

当然,也有一些东西肯定起不到作用。这些东西需要对 std::string 进行大量重构才能工作。以下是这几项:

  • 默认的 (LPCTSTR) 转换永远不会起作用。CString 使用了一个复杂的 StringData 对象方案,以便类对象的指针与字符串数据的存储一致。这使得可以直接解引用内存指针,就像上面的第四个‘printf’示例一样;
  • LockUnlockstd::string 类没有锁定机制。你需要将锁定操作放在字符串对象之外进行;
  • 引用计数。但我们有标准库中的智能指针!
  • 写时复制 (COW)。对于单线程程序使用小字符串来说,这无疑是一个好东西。但 COW 已被禁止使用在标准库中。请参阅 Herb Sutter 这里 和 Giovanni Dicanio 这里 的一些论述。

一些可能会让你吃亏的细节

你应该注意一些细节,否则它们**会**让你吃亏!

  • 仔细检查 Visual Studio 中的“高级项目设置”。特别是“使用 MFC”设置;
  • 仔细检查标准预编译头设置以及你的项目中仍然使用的任何‘stdafx.h’。我在不少项目中都忘记了这一点。删除“#include <afx.h>”和其他设置,或者转换为使用“pch.h”文件的较新约定。

好了,就这些了。祝你使用“SMX_String”愉快!

历史

  • 2019年9月29日:初始版本
© . All rights reserved.