C++字符串完全指南(2) - STL和ATL类

来源:互联网 发布:淘宝粘贴复制怎么弄 编辑:程序博客网 时间:2024/05/16 19:38
C++字符串完全指南(2) - STL和ATL类
STL类

STL只有一个字符串类,即basic_string。basic_string管理一个零结尾的字符数组。字符类型由模板参数决定。通常,basic_string被处理为不透明对象。可以获得一个只读指针来访问缓冲区,但写操作都是由basic_string的成员函数进行的。

basic_string预定义了二个特例string,含有char类型字符;which,含有wchar_t类型字符。没有内建的TCHAR特例,可用下面的代码实现

// 特例化typedef basic_string tstring; // TCHAR字符串// 构造string str = "char string"; // 从LPCSTR构造wstring wstr = L"wide char string"; // 从LPCWSTR构造tstring tstr = _T("TCHAR string"); // 从LPCTSTR构造// 数据萃取LPCSTR psz = str.c_str(); // 指向str缓冲区的只读指针LPCWSTR pwsz = wstr.c_str(); // 指向wstr缓冲区的只读指针LPCTSTR ptsz = tstr.c_str(); // 指向tstr缓冲区的只读指针

与_bstr_t 不同,basic_string不能在字符集之间进行转换。但是如果一个构造函数接受相应的字符类型,可以将由c_str()返回的指针传递给这个构造函数。例如

// 从basic_string构造_bstr_t _bstr_t bs1 = str.c_str();  // 从LPCSTR构造 _bstr_t_bstr_t bs2 = wstr.c_str(); // 从LPCWSTR构造 _bstr_t
ATL类
CComBSTR

CComBSTR 是ATL的BSTR包装类。某些情况下比_bstr_t 更有用。最主要的是,CComBSTR允许操作隐含BSTR。就是说,传递一个CComBSTR对象给COM方法时,CComBSTR对象会自动管理BSTR内存。例如,要调用下面的接口函数

// 简单接口struct IStuff : public IUnknown{  // 略去COM程序...  STDMETHOD(SetText)(BSTR bsText);  STDMETHOD(GetText)(BSTR* pbsText);};

CComBSTR 有一个BSTR操作方法,能将BSTR直接传递给SetText()。还有一个引用操作(operator &)方法,返回BSTR*,将BSTR*传递给需要它的有关函数。

CComBSTR bs1;CComBSTR bs2 = "new text";pStuff->GetText ( &bs1 );       // ok, 取得内部BSTR地址  pStuff->SetText ( bs2 );        // ok, 调用BSTR转换  pStuff->SetText ( (BSTR) bs2 ); // cast ok, 同上

CComVariant
CComBSTR有类似于 _bstr_t 的构造函数。但没有内建MBCS字符串的转换函数。可以调用ATL宏进行转换。

// 构造CComBSTR bs1 = "char string"; // 从LPCSTR构造CComBSTR bs2 = L"wide char string"; // 从LPCWSTR构造CComBSTR bs3 = bs1; // 拷贝CComBSTRCComBSTR bs4;bs4.LoadString ( IDS_SOME_STR ); // 从字符串表加载// 数据萃取BSTR bstr1 = bs1; // 返回内部BSTR,但不可修改!BSTR bstr2 = (BSTR) bs1; // cast ok, 同上BSTR bstr3 = bs1.Copy(); // 拷贝bs1, 返回BSTRBSTR bstr4;bstr4 = bs1.Detach(); // bs1不再管理它的BSTR// ...SysFreeString ( bstr3 );SysFreeString ( bstr4 );

上面的最后一个示例用到了Detach()方法。该方法调用后,CComBSTR对象就不再管理它的BSTR或其相应内存。所以bstr4就必须调用SysFreeString()。

最后讨论一下引用操作符(operator &)。它的超越使得有些STL集合(如list)不能直接使用CComBSTR。在集合上使用引用操作返回指向包容类的指针。但是在CComBSTR上使用引用操作,返回的是BSTR*,不是CComBSTR*。不过可以用ATL的CAdapt类来解决这个问题。例如,要建立一个CComBSTR的队列,可以声明为

  std::list< CAdapt> bstr_list;

CAdapt 提供集合所需的操作,是隐含于代码的。这时使用bstr_list 就象在操作一个CComBSTR队列。

CComVariant

CComVariant 是VARIANT的包装类。但与 _variant_t 不同,它的VARIANT不是隐含的,可以直接操作类里的VARIANT成员。CComVariant 提供多种构造函数和多类型操作。这里只介绍与字符串有关的操作。

// 构造CComVariant v1 = "char string";       // 从LPCSTR构造CComVariant v2 = L"wide char string"; // 从LPCWSTR构造CComBSTR bs1 = "BSTR bob";CComVariant v3 = (BSTR) bs1;          // 从BSTR拷贝// 数据萃取CComBSTR bs2 = v1.bstrVal;            // 从VARIANT提取BSTR

跟_variant_t 不同,CComVariant没有不同VARIANT类型之间的转换操作。必须直接操作VARIANT成员,并确定该VARIANT的类型无误。调用ChangeType()方法可将CComVariant数据转换为BSTR。

CComVariant v4 = ... // 从某种类型初始化 v4CComBSTR bs3;if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))    bs3 = v4.bstrVal;

跟 _variant_t 一样,CComVariant不能直接转换为MBCS字符串。要建立一个过渡的_bstr_t 变量,用其它提供转换Unicode到MBCS的类函数,或ATL转换宏来转换。

ATL转换宏

ATL转换宏

ATL的字符串转换宏可以方便地转换不同编码的字符,用在函数中很有效。宏按照[source type]2[new type] 或 [source type]2C[new type]格式命名。后者转换为一个常量指针 (名字内含"C")。类型缩写如下


 AMBCS字符串,char* (A for ANSI)
 WUnicode字符串,wchar_t* (W for wide)
 TTCHAR字符串,TCHAR*
 OLEOLECHAR字符串,OLECHAR* (实际等于W)
 BSTRBSTR (只用于目的类型)

例如,W2A() 将Unicode字符串转换为MBCS字符串,T2CW()将TCHAR字符串转换为Unicode字符串常量。

要使用宏转换,程序中要包含atlconv.h头文件。可以在非ATL程序中使用宏转换,因为头文件不依赖其它的ATL,也不需要 _Module全局变量。如在函数中使用转换宏,在函数起始处先写上USES_CONVERSION宏。它表明某些局部变量由宏控制使用。

转换得到的结果字符串,只要不是BSTR,都存储在堆栈中。如果要在函数外使用这些字符串,就要将这些字符串拷贝到其它的字符串类。如果结果是BSTR,内存不会自动释放,因此必须将返回值分配给一个BSTR变量或BSTR的包装类,以避免内存泄露。

下面是若干宏转换示例

// 带有字符串的函数void Foo ( LPCWSTR wstr );void Bar ( BSTR bstr );// 返回字符串的函数void Baz ( BSTR* pbstr );#include main(){using std::string;USES_CONVERSION;    // 声明局部变量由宏控制使用// 示例1送一个MBCS字符串到Foo()LPCSTR psz1 = "Bob";string str1 = "Bob";Foo ( A2CW(psz1) );  Foo ( A2CW(str1.c_str()) );// 示例2将MBCS字符串和Unicode字符串送到Bar()LPCSTR psz2 = "Bob";LPCWSTR wsz = L"Bob";BSTR bs1;CComBSTR bs2;bs1 = A2BSTR(psz2);         // 创建 BSTR  bs2.Attach ( W2BSTR(wsz) ); // 同上,分配到CComBSTRBar ( bs1 );  Bar ( bs2 );SysFreeString ( bs1 );      // 释放bs1  // 不必释放bs2,由CComBSTR释放。// 示例3转换由Baz()返回的BSTRBSTR bs3 = NULL;string str2;Baz ( &bs3 );          // Baz() 填充bs3内容str2 = W2CA(bs3);      // 转换为MBCS字符串  SysFreeString ( bs3 ); // 释放bs3}
可以看到,向一个需要某种类型参数的函数传递另一种类型的参数,用宏转换是非常方便的。
原创粉丝点击