CString 和 std::string 集成






4.96/5 (11投票s)
仅 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
,我们可以用 typedef
将 CString
重命名为我们的新类。我们甚至可以用宏重命名一个“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::string
和 MFC::CString
的功能。
现在我们可以用“String
”做任何我们想做的事情。在上面的例子中,你可以看到你可以同时使用“c_str()
”和“GetString()
”,并且“Left(n)
”也起作用。无需去检查数百万行代码来消除所有那些“Left()
”。😊
未起作用的部分
当然,也有一些东西肯定起不到作用。这些东西需要对 std::string
进行大量重构才能工作。以下是这几项:
- 默认的 (LPCTSTR) 转换永远不会起作用。
CString
使用了一个复杂的StringData
对象方案,以便类对象的指针与字符串数据的存储一致。这使得可以直接解引用内存指针,就像上面的第四个‘printf
’示例一样; Lock
和Unlock
。std::string
类没有锁定机制。你需要将锁定操作放在字符串对象之外进行;- 引用计数。但我们有标准库中的智能指针!
- 写时复制 (COW)。对于单线程程序使用小字符串来说,这无疑是一个好东西。但 COW 已被禁止使用在标准库中。请参阅 Herb Sutter 这里 和 Giovanni Dicanio 这里 的一些论述。
一些可能会让你吃亏的细节
你应该注意一些细节,否则它们**会**让你吃亏!
- 仔细检查 Visual Studio 中的“高级项目设置”。特别是“使用 MFC”设置;
- 仔细检查标准预编译头设置以及你的项目中仍然使用的任何‘stdafx.h’。我在不少项目中都忘记了这一点。删除“
#include <afx.h>
”和其他设置,或者转换为使用“pch.h”文件的较新约定。
好了,就这些了。祝你使用“SMX_String
”愉快!
历史
- 2019年9月29日:初始版本