C++字符串完全指引之二:字符串封装类
2010-10-15 09:08:04 来源:Web开发网CLR 和 VC 7 类
System::String是用来处理字符串的.NET类。在内部,一个String对象包含一个不可改变的字符串序列。任何对String对象的操作实际上都是返回了一个新的String对象,因为原始的对象是不可改变的。String的一个特性是如果你有不止一个String对象包含相同的字符序列,它们实际上是指向相同的对象的。相对于C++的使用扩展是增加了一个新的字符串常量前缀S,S用来代表一个受控的字符串常量(a managed string literal)。
// Constructing
String* ms = S"This is a nice managed string";
你可以传递一个非受控的字符串来创建一个String对象,但是样会比使用受控字符串来创建String对象造成效率的微小损失。这是因为所有以S作为前缀的相同的字符串实例都代表同样的对象,但这对非受控对象是不适用的。下面的代码清楚地阐明了这一点:
String* ms1 = S"this is nice";
String* ms2 = S"this is nice";
String* ms3 = L"this is nice";
Console::WriteLine ( ms1 == ms2 ); // prints true
Console::WriteLine ( ms1 == ms3); // prints false
正确的比较可能没有使用S前缀的字符串的方法是使用String::CompareTo()
Console::WriteLine ( ms1->CompareTo(ms2) );
Console::WriteLine ( ms1->CompareTo(ms3) );
上面的两行代码都会打印0,0表示两个字符串相等。String和MFC 7 CString之间的转换是很容易的。CString有一个向LPCTSTR的转换操作,而String有两个接收char* 和 wchar_t*的构造函数,因此你可以把一个CString变量直接传给一个String的构造函数。
CString s1 ( "hello world" );
String* s2 ( s1 ); // copy from a CString
反方向的转换也很类似
String* s1 = S"Three cats";
CString s2 ( s1 );
这也许会使你感到一点迷惑,但是它确实是起作用的。因为从VS.NET 开始,CString 有了一个接收String 对象的构造函数。
CStringT ( System::String* pString );
对于一些快速操作,你可能想访问底层的字符串:
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* ,我们需要固定它,否则垃圾收集器或许会在我们正在管理它的内容的时候移动了它。
在 printf-style 格式函数中使用字符串类
当你在printf()或者类似的函数中使用字符串封装类时你必须十分小心。这些函数包括sprintf()和它的变体,还有TRACE和ATLTRACE宏。因为这些函数没有对添加的参数的类型检查,你必须小心,只能传给它们C语言风格的字符串指针,而不是一个完整的字符串类。
例如,要把一个_bstr_t 字符串传给ATLTRACE(),你必须使用显式转换(LPCSTR) 或者(LPCWSTR):
_bstr_t bs = L"Bob!";
ATLTRACE("The string is: %s in line %d
", (LPCSTR) bs, nLine);
如果你忘了使用转换符而把整个_bstr_t对象传给了函数,将会显示一些毫无意义的输出,因为_bstr_t保存的内部数据会全部被输出。
更多精彩
赞助商链接