C++字符串完全指南(2) - MFC类

MFC类

 

MFC类

CString

MFC的CString含有TCHAR,它的实际字符类型取决于预处理标记的设置。通常,CString象STL字符串一样是不透明对象,只能用CString的方法来修改。CString比STL字符串更优越的是它的构造函数接受MBCS和Unicode字符串。并且可以转换为LPCTSTR,因此可以向接受LPCTSTR的函数直接传递CString对象,不必调用c_str()方法。

// 构造
CString s1 = "char string"; // 从LPCSTR构造
CString s2 = L"wide char string"; // 从LPCWSTR构造
CString s3 ( ' ', 100 ); // 预分配100字节,填充空格
CString s4 = "New window text";
// 可以在LPCTSTR处使用CString:
SetWindowText ( hwndSomeWindow, s4 );
// 或者,显式地做强制类型转换:
SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );

也可以从字符串表加载字符串。CString通过LoadString()来构造对象。用Format()方法可有选择地从字符串表读取一定格式的字符串。

// 从字符串表构造/加载
CString s5 ( (LPCTSTR) IDS_SOME_STR );  // 从字符串表加载
CString s6, s7;
// 从字符串表加载
  s6.LoadString ( IDS_SOME_STR );
// 从字符串表加载打印格式的字符串
  s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... );

第一个构造函数看上去有点怪,但它的确是文档标定的字符串加载方式。

注意,CString只允许一种强制类型转换,即强制转换为LPCTSTR。强制转换为LPTSTR (非常量指针)是错误的。按照老习惯,将CString强制转换为LPTSTR只能伤害自己。有时在程序中没有发现出错,那只是碰巧。转换到非常量指针的正确方法是调用GetBuffer()方法。

下面以往队列加入元素为例说明如何正确地使用CString:

CString str = _T("new text");
LVITEM item = {0};
item.mask = LVIF_TEXT;
  item.iItem = 1;
  item.pszText = (LPTSTR)(LPCTSTR) str; // 错!
  item.pszText = str.GetBuffer(0);      // 正确
ListView_SetItem ( &item );
  str.ReleaseBuffer();  // 将队列返回给str

pszText成员是LPTSTR,一个非常量指针,因此要用str的GetBuffer()。GetBuffer()的参数是CString分配的最小缓冲区。如果要分配一个1K的TCHAR,调用GetBuffer(1024)。参数为0,只返回指向字符串的指针。

上面示例的出错语句可以通过编译,甚至可以正常工作,如果恰好就是这个类型。但这不证明语法正确。进行非常量的强制类型转换,打破了面向对象的封装原则,并逾越了CString的内部操作。如果你习惯进行这样的强制类型转换,终会遇到出错,可你未必知道错在何处,因为你到处都在做这样的转换,而代码也都能运行。

 

知道为什么人们总在抱怨有缺陷的软件吗?不正确的代码就臭虫的滋生地。然道你愿意编写明知有错的代码让臭虫有机可乘?还是花些时间学习CString的正确用法让你的代码能够100%的正确吧。

CString还有二个函数能够从CString中得到BSTR,并在必要时转换成Unicode。那就是AllocSysString()和SetSysString()。除了SetSysString()使用BSTR*参数外,二者一样。

// 转换成BSTR
CString s5 = "Bob!";
BSTR bs1 = NULL, bs2 = NULL;
bs1 = s5.AllocSysString();
  s5.SetSysString ( &bs2 );
// ...
  SysFreeString ( bs1 );
  SysFreeString ( bs2 );

COleVariant 与CComVariant 非常相似。COleVariant 继承于VARIANT,可以传递给需要VARIANT的函数。但又与CComVariant 不同,COleVariant 只有一个LPCTSTR的构造函数,不提供单独的LPCSTR和LPCWSTR的构造函数。在大多情况下,没有问题,因为总是愿意把字符串处理为LPCTSTR。但你必须知道这点。COleVariant 也有接受CString的构造函数。

// 构造
CString s1 = _T("tchar string");
COleVariant v1 = _T("Bob"); // 从LPCTSTR构造
COleVariant v2 = s1; // 从CString拷贝

对于CComVariant,必须直接处理VARIANT成员,用ChangeType()方法在必要时将其转换为字符串。但是,COleVariant::ChangeType() 在转换失败时会抛出异常,而不是返回HRESULT的出错码。

// 数据萃取
COleVariant v3 = ...; // 从某种类型构造v3
BSTR bs = NULL;
try
    {
    v3.ChangeType ( VT_BSTR );
    bs = v3.bstrVal;
    }
  catch ( COleException* e )
    {
    // 出错,无法转换
    }
SysFreeString ( bs );

WTL类

 

WTL类

CString

WTL的CString与MFC的CString的行为完全相同,参阅上面关于MFC CString的说明即可。

CLR 及 VC 7 类

System::String 是.NET的字符串类。在其内部,String对象是一个不变的字符序列。任何操作String对象的String方法都返回一个新的String对象,因为原有的String对象要保持不变。String类有一个特性,当多个String都指向同一组字符集时,它们其实是指向同一个对象。Managed Extensions C++ 的字符串有一个新的前缀S,用来表明是一个managed string字符串。

// 构造
String* ms = S"This is a nice managed string";

可以用unmanaged string字符串来构造String对象,但不如用managed string构造String对象有效。原因是所有相同的具有S前缀的字符串都指向同一个对象,而unmanaged string没有这个特点。下面的例子可以说明得更清楚些:

String* ms1 = S"this is nice";
String* ms2 = S"this is nice";
String* ms3 = L"this is nice";
Console::WriteLine ( ms1 == ms2 ); // 输出true
Console::WriteLine ( ms1 == ms3);  // 输出false

要与没有S前缀的字符串做比较,用String::CompareTo()方法来实现,如:

  Console::WriteLine ( ms1->CompareTo(ms2) );
  Console::WriteLine ( ms1->CompareTo(ms3) );

二者都输出0,说明字符串相等。

在String和MFC 7的CString之间转换很容易。CString可以转换为LPCTSTR,String有接受char* 和 wchar_t* 的二种构造函数。因此可以直接把CString传递给String的构造函数:

  CString s1 ( "hello world" );
  String* s2 ( s1 );  // 从CString拷贝

反向转换的方法也类似:

  String* s1 = S"Three cats";
  CString s2 ( s1 );

可能有点迷惑。从VS.NET开始,CString有一个接受String对象的构造函数,所以是正确的。

  CStringT ( System::String* pString );

为了加速操作,有时可以用基础字符串(underlying string):

String* s1 = S"Three cats";
Console::WriteLine ( s1 );
const __wchar_t __pin* pstr = PtrToStringChars(s1);
for ( int i = 0; i < wcslen(pstr); i++ )
    (*const_cast<__wchar_t*>(pstr+i))++;
Console::WriteLine ( s1 );

PtrToStringChars() 返回指向基础字符串的 const __wchar_t* 指针,可以防止在操作字符串时,垃圾收集器去除该字符串。
 

你可能感兴趣的:(C++字符串完全指南(2) - MFC类)