欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
c++字符串完全指引之二 —— 字符串封裝類(lèi) - 悠悠我心

C++字符串完全指引之二 —— 字符串封裝類(lèi)


原著(zhù):Michael Dunn

作者:Chengjie Sun


原文出處:CodeProject:The Complete Guide to C++ Strings, Part II


引言

  因為C語(yǔ)言風(fēng)格的字符串容易出錯且不易管理,黑客們甚至利用可能存在的緩沖區溢出bug把C語(yǔ)言風(fēng)格的字符串作為攻擊目標,所以出現了很多字符串封裝類(lèi)。不幸的是,在某些場(chǎng)合下我們不知道該使用哪個(gè)字符串類(lèi),也不知道怎樣把一個(gè)C風(fēng)格的字符串轉換成一個(gè)字符串封裝類(lèi)。
  這篇文章將介紹所有在Win32 API, MFC, STL, WTL 和 Visual C++ 運行庫中出現的字符串類(lèi)型。我將描述每一個(gè)類(lèi)的用法,告訴大家怎樣創(chuàng )建每一個(gè)類(lèi)的對象以及怎樣把一個(gè)類(lèi)轉換成其他類(lèi)。受控字符串和Visual C++ 7中的類(lèi)兩部分是Nish完成的。
  為了更好的從這篇文章中受益,你必須要明白不同的字符類(lèi)型和編碼,這些內容我在第一部分中介紹過(guò)。

Rule #1 of string classes

  使用cast來(lái)實(shí)現類(lèi)型轉換是不好的做法,除非有文檔明確指出這種轉換可以使用。
促使我寫(xiě)這兩篇文章的原因是字符串類(lèi)型轉換中經(jīng)常遇到的一些問(wèn)題。當我們使用cast把字符串從類(lèi)型X轉換到類(lèi)型Z的時(shí)候,我們不知道為什么代碼不能正常工作。各種各樣的字符串類(lèi)型,尤其是BSTR,幾乎沒(méi)有在任何一個(gè)地方的文檔中被明確的指出可以用cast來(lái)實(shí)現類(lèi)型轉換。所以我想一些人可能會(huì )使用cast來(lái)實(shí)現類(lèi)型轉換并希望這種轉換能夠正常工作。
  除非源字符串是一個(gè)被明確指明支持轉換操作符的字符串包裝類(lèi),否則cast不對字符串做任何轉換。對常量字符串使用cast不會(huì )起到任何作用,所以下面的代碼:

void SomeFunc ( LPCWSTR widestr );main(){  SomeFunc ( (LPCWSTR) "C:\\foo.txt" );  // WRONG!}      
  肯定會(huì )失敗。它可以被編譯,因為cast操作會(huì )撤消編譯器的類(lèi)型檢查。但是,編譯可以通過(guò)并不能說(shuō)明代碼是正確的。
  在下面的例子中,我將會(huì )指明cast在什么時(shí)候使用是合法的。
C-style strings and typedefs

  正如我在第一部分中提到的,windows APIs 是用TCHARs來(lái)定義的,在編譯時(shí),它可以根據你是否定義_MBCS或者_UNICODE被編譯成MBCS或者Unicode字符。你可以參看第一部分中對TCHAR的完整描述,這里為了方便,我列出了字符的typedefs

TypeMeaning
WCHARUnicode character (wchar_t)
TCHARMBCS or Unicode character, depending on preprocessor settings
LPSTR string of char (char*)
LPCSTRconstant string of char (const char*)
LPWSTR string of WCHAR (WCHAR*)
LPCWSTR constant string of WCHAR (const WCHAR*)
LPTSTR string of TCHAR (TCHAR*)
LPCTSTR constant string of TCHAR (const TCHAR*)

  一個(gè)增加的字符類(lèi)型是OLETYPE。它表示自動(dòng)化接口(如word提供的可以使你操作文檔的接口)中使用的字符類(lèi)型。這種類(lèi)型一般被定義成wchar_t,然而如果你定義了OLE2ANSI預處理標記,OLECHAR將會(huì )被定義成char類(lèi)型。我知道現在已經(jīng)沒(méi)有理由定義OLE2ANSI(從MFC3以后,微軟已經(jīng)不使用它了),所以從現在起我將把OLECHAR當作Unicode字符。
這里給出你將會(huì )看到的一些OLECHAR相關(guān)的typedefs:

TypeMeaning
OLECHAR Unicode character (wchar_t)
LPOLESTR string of OLECHAR (OLECHAR*)
LPCOLESTR constant string of OLECHAR (const OLECHAR*)

  還有兩個(gè)用于包圍字符串和字符常量的宏定義,它們可以使同樣的代碼被用于MBCS和Unicode builds :

Type Meaning
_T(x)Prepends L to the literal in Unicode builds.
OLESTR(x)Prepends L to the literal to make it an LPCOLESTR.

  在文檔或例程中,你還會(huì )看到好多_T的變體。有四個(gè)等價(jià)的宏定義,它們是TEXT, _TEXT, __TEXT和__T,它們都起同樣的做用。

COM 中的字符串 —— BSTR 和 VARIANT

  很多自動(dòng)化和COM接口使用BSTR來(lái)定義字符串。BSTRs中有幾個(gè)"陷阱",所以這里我用單獨的部分來(lái)說(shuō)明它。
  BSTR 是 Pascal-style 字符串(字符串長(cháng)度被明確指出)和C-style字符串(字符串的長(cháng)度要通過(guò)尋找結束符來(lái)計算)的混合產(chǎn)物。一個(gè)BSTR是一個(gè)Unicode字符串,它的長(cháng)度是預先考慮的,并且它還有一個(gè)0字符作為結束標記。下面是一個(gè)BSTR的示例:

 

06 00 00 0042 006F 0062 0000 00
--length--BobEOS

  注意字符串的長(cháng)度是如何被加到字符串數據中的。長(cháng)度是DWORD類(lèi)型的,保存了字符串中包含的字節數,但不包括結束標記。在這個(gè)例子中,"Bob"包含3個(gè)Unicode字符(不包括結束符),總共6個(gè)字節。字符串的長(cháng)度被預先存儲好,以便當一個(gè)BSTR在進(jìn)程或者計算機之間被傳遞時(shí),COM庫知道多少數據需要傳送。(另一方面,一個(gè)BSTR能夠存儲任意數據塊,而不僅僅是字符,它還可以包含嵌入在數據中的0字符。然而,由于這篇文章的目的,我將不考慮那些情況)。
  在 C++ 中,一個(gè) BSTR 實(shí)際上就是一個(gè)指向字符串中第一個(gè)字符的指針。它的定義如下:

BSTR bstr = NULL;  bstr = SysAllocString ( L"Hi Bob!" );   if ( NULL == bstr )    // out of memory error   // Use bstr here... SysFreeString ( bstr );      
自然的,各種各樣的BSTR封裝類(lèi)為你實(shí)現內存管理。
  另外一個(gè)用在自動(dòng)化接口中的變量類(lèi)型是VARIANT。它被用來(lái)在無(wú)類(lèi)型(typeless)語(yǔ)言,如Jscript和VBScript,來(lái)傳遞數據。一個(gè)VARIANT可能含有很多不同類(lèi)型的數據,例如long和IDispatch*。當一個(gè)VARIANT包含一個(gè)字符串,字符串被存成一個(gè)BSTR。當我后面講到VARIANT封裝類(lèi)時(shí),我會(huì )對VARIANT多些介紹。

字符串封裝類(lèi)

  到目前為止,我已經(jīng)介紹了各種各樣的字符串。下面,我將說(shuō)明封裝類(lèi)。對于每個(gè)封裝類(lèi),我將展示怎樣創(chuàng )建一個(gè)對象及怎樣把它轉換成一個(gè)C語(yǔ)言風(fēng)格的字符串指針。C語(yǔ)言風(fēng)格的字符串指針對于A(yíng)PI的調用,或者創(chuàng )建一個(gè)不同的字符串類(lèi)對象經(jīng)常是必需的。我不會(huì )介紹字符串類(lèi)提供的其他操作,比如排序和比較。
  重復一遍,除非你確切的明白結果代碼將會(huì )做什么,否則不要盲目地使用cast來(lái)實(shí)現類(lèi)型轉換。

CRT提供的類(lèi)

_bstr_t
  _bstr_t是一個(gè)對BSTR的完整封裝類(lèi),實(shí)際上它隱藏了底層的BSTR。它提供各種構造函數和操作符來(lái)訪(fǎng)問(wèn)底層的C語(yǔ)言風(fēng)格的字符串。然而,_bstr_t卻沒(méi)有訪(fǎng)問(wèn)BSTR本身的操作符,所以一個(gè)_bstr_t類(lèi)型的字符串不能被作為輸出參數傳給一個(gè)COM方法。如果你需要一個(gè)BSTR*參數,使用ATL類(lèi)CComBSTR是比較容易的方式。
  一個(gè)_bstr_t字符串能夠傳給一個(gè)接收參數類(lèi)型為BSTR的函數,只是因為下列3個(gè)條件同時(shí)滿(mǎn)足。首先,_bstr_t有一個(gè)向wchar_t*轉換的轉換函數;其次,對編譯器而言,因為BSTR的定義,wchar_t*和BSTR有同樣的含義;第三,_bstr_t內部含有的wchar_t*指向一片按BSTR的形式存儲數據的內存。所以,即使沒(méi)有文檔說(shuō)明,_bstr_t可以轉換成BSTR,這種轉換仍然可以正常進(jìn)行。
// Constructing_bstr_t bs1 = "char string";       // construct from a LPCSTR_bstr_t bs2 = L"wide char string"; // construct from a LPCWSTR_bstr_t bs3 = bs1;                 // copy from another _bstr_t_variant_t v = "Bob";_bstr_t bs4 = v;                   // construct from a _variant_t that has a string // Extracting dataLPCSTR psz1 = bs1;              // automatically converts to MBCS stringLPCSTR psz2 = (LPCSTR) bs1;     // cast OK, same as previous lineLPCWSTR pwsz1 = bs1;            // returns the internal Unicode stringLPCWSTR pwsz2 = (LPCWSTR) bs1;  // cast OK, same as previous lineBSTR    bstr = bs1.copy();      // copies bs1, returns it as a BSTR   // ...SysFreeString ( bstr );      
  注意_bstr_t也提供char*和wchar_t*之間的轉換操作符。這是一個(gè)值得懷疑的設計,因為即使它們是非常量字符串指針,你也一定不能使用這些指針去修改它們指向的緩沖區的內容,因為那將破壞內部的BSTR結構。

_variant_t
  _variant_t是一個(gè)對VARIANT的完整封裝,它提供很多構造函數和轉換函數來(lái)操作一個(gè)VARIANT可能包含的大量的數據類(lèi)型。這里,我將只介紹與字符串有關(guān)的操作。
// Constructing_variant_t v1 = "char string";       // construct from a LPCSTR_variant_t v2 = L"wide char string"; // construct from a LPCWSTR_bstr_t bs1 = "Bob";_variant_t v3 = bs1;                 // copy from a _bstr_t object // Extracting data_bstr_t bs2 = v1;           // extract BSTR from the VARIANT_bstr_t bs3 = (_bstr_t) v1; // cast OK, same as previous line      
注意
  如果類(lèi)型轉換不能被執行,_variant_t方法能夠拋出異常,所以應該準備捕獲_com_error異常。

還需要注意的是
  沒(méi)有從一個(gè)_variant_t變量到一個(gè)MBCS字符串的直接轉換。你需要創(chuàng )建一個(gè)臨時(shí)的_bstr_t變量,使用提供Unicode到MBCS轉換的另一個(gè)字符串類(lèi)或者使用一個(gè)ATL轉換宏。
  不像_bstr_t,一個(gè)_variant_t變量可以被直接作為參數傳遞給一個(gè)COM方法。_variant_t
  繼承自VARIANT類(lèi)型,所以傳遞一個(gè)_variant_t來(lái)代替VARIANT變量是C++語(yǔ)言所允許的。

STL 類(lèi)
  STL只有一個(gè)字符串類(lèi),basic_string。一個(gè)basic_string管理一個(gè)以0做結束符的字符串數組。字符的類(lèi)型是basic_string模般的參數??偟膩?lái)說(shuō),一個(gè)basic_string類(lèi)型的變量應該被當作不透明的對象。你可以得到一個(gè)指向內部緩沖區的只讀指針,但是任何寫(xiě)操作必須使用basic_string的操作符和方法。
  basic_string有兩個(gè)預定義的類(lèi)型:包含char的string類(lèi)型和包含wchar_t的wstring類(lèi)型。這里沒(méi)有內置的包含TCHAR的類(lèi)型,但是你可以使用下面列出的代碼來(lái)實(shí)現。
// Specializationstypedef basic_string tstring; // string of TCHARs // Constructingstring str = "char string";         // construct from a LPCSTRwstring wstr = L"wide char string"; // construct from a LPCWSTRtstring tstr = _T("TCHAR string");  // construct from a LPCTSTR // Extracting dataLPCSTR psz = str.c_str();    // read-only pointer to str‘‘s bufferLPCWSTR pwsz = wstr.c_str(); // read-only pointer to wstr‘‘s bufferLPCTSTR ptsz = tstr.c_str(); // read-only pointer to tstr‘‘s buffer
  不像_bstr_t,一個(gè)basic_string變量不能在字符集之間直接轉換。然而,你可以傳遞由c_str()返回的指針給另外一個(gè)類(lèi)的構造函數(如果這個(gè)類(lèi)的構造函數接受這種字符類(lèi)型)。例如:
// Example, construct _bstr_t from basic_string_bstr_t bs1 = str.c_str();  // construct a _bstr_t from a LPCSTR_bstr_t bs2 = wstr.c_str(); // construct a _bstr_t from a LPCWSTR      
ATL 類(lèi)

CComBSTR
  CComBSTR 是 ATL 中的 BSTR 封裝類(lèi),它在某些情況下比_bstr_t有用的多。最引人注意的是CComBSTR允許訪(fǎng)問(wèn)底層的BSTR,這意味著(zhù)你可以傳遞一個(gè)CComBSTR對象給COM的方法。CComBSTR對象能夠替你自動(dòng)的管理BSTR的內存。例如,假設你想調用下面這個(gè)接口的方法:
// Sample interface:struct IStuff : public IUnknown{  // Boilerplate COM stuff omitted...  STDMETHOD(SetText)(BSTR bsText);  STDMETHOD(GetText)(BSTR* pbsText);};      
  CComBSTR有一個(gè)操作符--BSTR方法,所以它能直接被傳給SetText()函數。還有另外一個(gè)操作--&,這個(gè)操作符返回一個(gè)BSTR*。所以,你可以對一個(gè)CComBSTR對象使用&操作符,然后把它傳給需要BSTR*參數的函數。
CComBSTR bs1;CComBSTR bs2 = "new text";   pStuff->GetText ( &bs1 );       // ok, takes address of internal BSTR  pStuff->SetText ( bs2 );        // ok, calls BSTR converter  pStuff->SetText ( (BSTR) bs2 ); // cast ok, same as previous line      
  CComBSTR有和_bstr_t相似的構造函數,然而卻沒(méi)有內置的向MBCS字符串轉換的函數。因此,你需要使用一個(gè)ATL轉換宏。
// ConstructingCComBSTR bs1 = "char string";       // construct from a LPCSTRCComBSTR bs2 = L"wide char string"; // construct from a LPCWSTRCComBSTR bs3 = bs1;                 // copy from another CComBSTRCComBSTR bs4;  bs4.LoadString ( IDS_SOME_STR );  // load string from string table// Extracting dataBSTR bstr1 = bs1;        // returns internal BSTR, but don‘‘t modify it!BSTR bstr2 = (BSTR) bs1; // cast ok, same as previous lineBSTR bstr3 = bs1.Copy(); // copies bs1, returns it as a BSTRBSTR bstr4;  bstr4 = bs1.Detach();  // bs1 no longer manages its BSTR  // ...  SysFreeString ( bstr3 );  SysFreeString ( bstr4 );      
  注意在上個(gè)例子中使用了Detach()方法。調用這個(gè)方法后,CComBSTR對象不再管理它的BSTR字符串或者說(shuō)它對應的內存。這就是bstr4需要調用SysFreeString()的原因。
  做一個(gè)補充說(shuō)明:重載的&操作符意味著(zhù)在一些STL容器中你不能直接使用CComBSTR變量,比如list。容器要求&操作符返回一個(gè)指向容器包含的類(lèi)的指針,但是對CComBSTR變量使用&操作符返回的是BSTR*,而不是CComBSTR*。然而,有一個(gè)ATL類(lèi)可以解決這個(gè)問(wèn)題,這個(gè)類(lèi)是CAdapt。例如,你可以這樣聲明一個(gè)CComBSTR的list:
std::list< CAdapt<CComBSTR> > bstr_list;

  CAdapt提供容器所需要的操作符,但這些操作符對你的代碼是透明的。你可以把一個(gè)bstr_list當作一個(gè)CComBSTR的list來(lái)使用。

CComVariant
  CComVariant是VARIANT的封裝類(lèi)。然而,不像_variant_t,在CComVariant中VARIANT沒(méi)有被隱藏。事實(shí)上你需要直接訪(fǎng)問(wèn)VARIANT的成員。CComVariant提供了很多構造函數來(lái)對VARIANT能夠包含的多種類(lèi)型進(jìn)行處理。這里,我將只介紹和字符串相關(guān)的操作。

// ConstructingCComVariant v1 = "char string";       // construct from a LPCSTRCComVariant v2 = L"wide char string"; // construct from a LPCWSTRCComBSTR bs1 = "BSTR bob";CComVariant v3 = (BSTR) bs1;          // copy from a BSTR // Extracting dataCComBSTR bs2 = v1.bstrVal;            // extract BSTR from the VARIANT      
  不像_variant_t,這里沒(méi)有提供針對VARIANT包含的各種類(lèi)型的轉換操作符。正如上面介紹的,你必須直接訪(fǎng)問(wèn)VARIANT的成員并且確保這個(gè)VARIANT變量保存著(zhù)你期望的類(lèi)型。如果你需要把一個(gè)CComVariant類(lèi)型的數據轉換成一個(gè)BSTR類(lèi)型的數據,你可以調用ChangeType()方法。
CComVariant v4 = ... // Init v4 from somewhereCComBSTR bs3;   if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))    bs3 = v4.bstrVal;      
  像_variant_t一樣,CComVariant也沒(méi)有提供向MBCS字符串轉換的轉換操作。你需要創(chuàng )建一個(gè)_bstr_t類(lèi)型的中間變量,使用提供從Unicode到MBCS轉換的另一個(gè)字符串類(lèi),或者使用一個(gè)ATL的轉換宏。

ATL轉換宏

  ATL:轉換宏是各種字符編碼之間進(jìn)行轉換的一種很方便的方式,在函數調用時(shí),它們顯得非常有用。ATL轉換宏的名稱(chēng)是根據下面的模式來(lái)命名的[源類(lèi)型]2[新類(lèi)型]或者[源類(lèi)型]2C[新類(lèi)型]。據有第二種形式的名字的宏的轉換結果是常量指針(對應名字中的"C")。各種類(lèi)型的簡(jiǎn)稱(chēng)如下:
A: MBCS string, char* (A for ANSI)W: Unicode string, wchar_t* (W for wide)T: TCHAR string, TCHAR*OLE: OLECHAR string, OLECHAR* (in practice, equivalent to W)BSTR: BSTR (used as the destination type only)

  所以,W2A()宏把一個(gè)Unicode字符串轉換成一個(gè)MBCS字符串。T2CW()宏把一個(gè)TCHAR字符串轉轉成一個(gè)Unicode字符串常量。
  為了使用這些宏,需要先包含atlconv.h頭文件。你甚至可以在非ATL工程中包含這個(gè)頭文件來(lái)使用其中定義的宏,因為這個(gè)頭文件獨立于A(yíng)TL中的其他部分,不需要一個(gè)_Module全局變量。當你在一個(gè)函數中使用轉換宏時(shí),需要把USES_CONVERSION宏放在函數的開(kāi)頭。它定義了轉換宏所需的一些局部變量。
  當轉換的目的類(lèi)型是除了BSTR以外的其他類(lèi)型時(shí),被轉換的字符串是存在棧中的。所以,如果你想讓字符串的生命周期比當前的函數長(cháng),你需要把這個(gè)字符串拷貝到其他的字符串類(lèi)中。當目的類(lèi)型是BSTR時(shí),內存不會(huì )自動(dòng)被釋放,你必須把返回值賦給一個(gè)BSTR變量或者一個(gè)BSTR封裝類(lèi)以避免內存泄漏。
  下面是一些各種轉換宏的使用例子:

// Functions taking various strings:void Foo ( LPCWSTR wstr );void Bar ( BSTR bstr );// Functions returning strings:void Baz ( BSTR* pbstr );#include <atlconv.h>main(){using std::string;USES_CONVERSION;    // declare locals used by the ATL macros// Example 1: Send an MBCS string to Foo()LPCSTR psz1 = "Bob";string str1 = "Bob";   Foo ( A2CW(psz1) );  Foo ( A2CW(str1.c_str()) ); // Example 2: Send a MBCS and Unicode string to Bar()LPCSTR psz2 = "Bob";LPCWSTR wsz = L"Bob";BSTR bs1;CComBSTR bs2;   bs1 = A2BSTR(psz2);         // create a BSTR  bs2.Attach ( W2BSTR(wsz) ); // ditto, assign to a CComBSTR   Bar ( bs1 );  Bar ( bs2 );   SysFreeString ( bs1 );      // free bs1 memory  // No need to free bs2 since CComBSTR will do it for us. // Example 3: Convert the BSTR returned by Baz()BSTR bs3 = NULL;string str2;  Baz ( &bs3 );          // Baz() fills in bs3  str2 = W2CA(bs3);      // convert to an MBCS string  SysFreeString ( bs3 ); // free bs3 memory}      
  正如你所看見(jiàn)的,當你有一個(gè)和函數所需的參數類(lèi)型不同的字符串時(shí),使用這些轉換宏是非常方便的。

MFC類(lèi)

CString
  因為一個(gè)MFC CString類(lèi)的對象包含TCHAR類(lèi)型的字符,所以確切的字符類(lèi)型取決于你所定義的預處理符號。大體來(lái)說(shuō),CString 很像STL string,這意味著(zhù)你必須把它當成不透明的對象,只能使用CString提供的方法來(lái)修改CString對象。CString有一個(gè)string所不具備的優(yōu)點(diǎn):CString具有接收MBCS和Unicode兩種字符串的構造函數,它還有一個(gè)LPCTSTR轉換符,所以你可以把CString對象直接傳給一個(gè)接收LPCTSTR的函數而不需要調用c_str()函數。
// ConstructingCString s1 = "char string";  // construct from a LPCSTRCString s2 = L"wide char string";  // construct from a LPCWSTRCString s3 ( ‘‘ ‘‘, 100 );  // pre-allocate a 100-byte buffer, fill with spacesCString s4 = "New window text";   // You can pass a CString in place of an LPCTSTR:  SetWindowText ( hwndSomeWindow, s4 );   // Or, equivalently, explicitly cast the CString:  SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );        
  你可以從你的字符串表中裝載一個(gè)字符串,CString的一個(gè)構造函數和LoadString()函數可以完成它。Format()方法能夠從字符串表中隨意的讀取一個(gè)具有一定格式的字符串?!    ?
// Constructing/loading from string tableCString s5 ( (LPCTSTR) IDS_SOME_STR );  // load from string tableCString s6, s7;   // Load from string table.  s6.LoadString ( IDS_SOME_STR );   // Load printf-style format string from the string table:  s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... );  
  第一個(gè)構造函數看起來(lái)有點(diǎn)奇怪,但是這實(shí)際上是文檔說(shuō)明的裝入一個(gè)字符串的方法。 注意,對一個(gè)CString變量,你可以使用的唯一合法轉換符是LPCTSTR。轉換成LPTSTR(非常量指針)是錯誤的。養成把一個(gè)CString變量轉換成LPTSTR的習慣將會(huì )給你帶來(lái)傷害,因為當你的程序后來(lái)崩潰時(shí),你可能不知道為什么,因為你到處都使用同樣的代碼而那時(shí)它們都恰巧正常工作。正確的得到一個(gè)指向緩沖區的非常量指針的方法是調用GetBuffer()方法。下面是正確的用法的一個(gè)例子,這段代碼是給一個(gè)列表控件中的項設定文字:
CString str = _T("new text");LVITEM item = {0};  item.mask = LVIF_TEXT;  item.iItem = 1;  item.pszText = (LPTSTR)(LPCTSTR) str; // WRONG!  item.pszText = str.GetBuffer(0);      // correct   ListView_SetItem ( &item );str.ReleaseBuffer();  // return control of the buffer to str      
  pszText成員是一個(gè)LPTSTR變量,一個(gè)非常量指針,因此你需要對str調用GetBuffer()。GetBuffer()的參數是你需要CString為緩沖區分配的最小長(cháng)度。如果因為某些原因,你需要一個(gè)可修改的緩沖區來(lái)存放1K TCHARs,你需要調用GetBuffer(1024)。把0作為參數時(shí),GetBuffer()返回的是指向字符串當前內容的指針。
  上面劃線(xiàn)的語(yǔ)句可以被編譯,在這種情況下,甚至可以正常起作用。但這并不意味著(zhù)這行代碼是正確的。通過(guò)使用非常量轉換,你已經(jīng)破壞了面向對象的封裝,并對CString的內部實(shí)現作了某些假定。如果你有這樣的轉換習慣,你終將會(huì )陷入代碼崩潰的境地。你會(huì )想代碼為什么不能正常工作了,因為你到處都使用同樣的代碼而那些代碼看起來(lái)是正確的。
  你知道人們總是抱怨現在的軟件的bug是多么的多嗎?軟件中的bug是因為程序員寫(xiě)了不正確的代碼。難道你真的想寫(xiě)一些你知道是錯誤的代碼來(lái)為所有的軟件都滿(mǎn)是bug這種認識做貢獻嗎?花些時(shí)間來(lái)學(xué)習使用CString的正確方法讓你的代碼在任何時(shí)間都正常工作把。
  CString 有兩個(gè)函數來(lái)從一個(gè) CString 創(chuàng )建一個(gè) BSTR。它們是 AllocSysString() 和SetSysString()。
// Converting to BSTRCString s5 = "Bob!";BSTR bs1 = NULL, bs2 = NULL;  bs1 = s5.AllocSysString();  s5.SetSysString ( &bs2 );  SysFreeString ( bs1 );  SysFreeString ( bs2 );      
COleVariant
  COleVariant和CComVariant.很相似。COleVariant繼承自VARIANT,所以它可以傳給接收VARIANT的函數。然而,不像CComVariant,COleVariant只有一個(gè)LPCTSTR構造函數。沒(méi)有對LPCSTR 和LPCWSTR的構造函數。在大多數情況下這不是一個(gè)問(wèn)題,因為不管怎樣你的字符串很可能是LPCTSTRs,但這是一個(gè)需要意識到的問(wèn)題。COleVariant還有一個(gè)接收CString參數的構造函數。
// ConstructingCString s1 = _T("tchar string");COleVariant v1 = _T("Bob"); // construct from an LPCTSTRCOleVariant v2 = s1; // copy from a CString      
  像CComVariant一樣,你必須直接訪(fǎng)問(wèn)VARIANT的成員。如果需要把VARIANT轉換成一個(gè)字符串,你應該使用ChangeType()方法。然而,COleVariant::ChangeType()如果失敗會(huì )拋出異常,而不是返回一個(gè)表示失敗的HRESULT代碼。
// Extracting dataCOleVariant v3 = ...; // fill in v3 from somewhereBSTR bs = NULL;  try    {    v3.ChangeType ( VT_BSTR );    bs = v3.bstrVal;    }  catch ( COleException* e )    {    // error, couldn‘‘t convert    }  SysFreeString ( bs );      

WTL 類(lèi)

CString
  WTL的CString的行為和MFC的 CString完全一樣,所以你可以參考上面關(guān)于MFC的 CString的介紹。

CLR 和 VC 7 類(lèi)

  System::String是用來(lái)處理字符串的.NET類(lèi)。在內部,一個(gè)String對象包含一個(gè)不可改變的字符串序列。任何對String對象的操作實(shí)際上都是返回了一個(gè)新的String對象,因為原始的對象是不可改變的。String的一個(gè)特性是如果你有不止一個(gè)String對象包含相同的字符序列,它們實(shí)際上是指向相同的對象的。相對于C++的使用擴展是增加了一個(gè)新的字符串常量前綴S,S用來(lái)代表一個(gè)受控的字符串常量(a managed string literal)。
// ConstructingString* ms = S"This is a nice managed string";      
  你可以傳遞一個(gè)非受控的字符串來(lái)創(chuàng )建一個(gè)String對象,但是樣會(huì )比使用受控字符串來(lái)創(chuàng )建String對象造成效率的微小損失。這是因為所有以S作為前綴的相同的字符串實(shí)例都代表同樣的對象,但這對非受控對象是不適用的。下面的代碼清楚地闡明了這一點(diǎn):
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      
正確的比較可能沒(méi)有使用S前綴的字符串的方法是使用String::CompareTo()
  Console::WriteLine ( ms1->CompareTo(ms2) );  Console::WriteLine ( ms1->CompareTo(ms3) );      
  上面的兩行代碼都會(huì )打印0,0表示兩個(gè)字符串相等。 String和MFC 7 CString之間的轉換是很容易的。CString有一個(gè)向LPCTSTR的轉換操作,而String有兩個(gè)接收char* 和 wchar_t*的構造函數,因此你可以把一個(gè)CString變量直接傳給一個(gè)String的構造函數。
CString s1 ( "hello world" );String* s2 ( s1 );  // copy from a CString      
反方向的轉換也很類(lèi)似
String* s1 = S"Three cats";CString s2 ( s1 );      
  這也許會(huì )使你感到一點(diǎn)迷惑,但是它確實(shí)是起作用的。因為從VS.NET 開(kāi)始,CString 有了一個(gè)接收String 對象的構造函數。
  CStringT ( System::String* pString );      
對于一些快速操作,你可能想訪(fǎng)問(wèn)底層的字符串:
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()返回一個(gè)指向底層字符串的const __wchar_t* ,我們需要固定它,否則垃圾收集器或許會(huì )在我們正在管理它的內容的時(shí)候移動(dòng)了它。

在 printf-style 格式函數中使用字符串類(lèi)

  當你在printf()或者類(lèi)似的函數中使用字符串封裝類(lèi)時(shí)你必須十分小心。這些函數包括sprintf()和它的變體,還有TRACE和ATLTRACE宏。因為這些函數沒(méi)有對添加的參數的類(lèi)型檢查,你必須小心,只能傳給它們C語(yǔ)言風(fēng)格的字符串指針,而不是一個(gè)完整的字符串類(lèi)。
  例如,要把一個(gè)_bstr_t 字符串傳給ATLTRACE(),你必須使用顯式轉換(LPCSTR) 或者(LPCWSTR):
_bstr_t bs = L"Bob!";ATLTRACE("The string is: %s in line %d\n", (LPCSTR) bs, nLine);

  如果你忘了使用轉換符而把整個(gè)_bstr_t對象傳給了函數,將會(huì )顯示一些毫無(wú)意義的輸出,因為_(kāi)bstr_t保存的內部數據會(huì )全部被輸出。

所有類(lèi)的總結

  兩個(gè)字符串類(lèi)之間進(jìn)行轉換的常用方式是:先把源字符串轉換成一個(gè)C語(yǔ)言風(fēng)格的字符串指針,然后把這個(gè)指針傳遞給目的類(lèi)型的構造函數。下面這張表顯示了怎樣把一個(gè)字符串轉換成一個(gè)C語(yǔ)言風(fēng)格的字符串指針以及哪些類(lèi)具有接收C語(yǔ)言風(fēng)格的字符串指針的構造函數。

Class  string type convert to char*? convert to const char*? convert to wchar_t*? convert to const wchar_t*? convert to BSTR? construct from char*? construct from wchar_t*?
_bstr_tBSTRyes cast1yes castyes cast1yes castyes2yesyes
_variant_tBSTRnononocast to
_bstr_t3
cast to
_bstr_t3
yesyes
stringMBCSnoyes c_str() methodnononoyesno
wstringUnicodenononoyes c_str() methodnonoyes
CComBSTRBSTRnononoyes cast to BSTRyes castyesyes
CComVariantBSTRnononoyes4yes4yesyes
CString TCHARno6in MBCS
builds, cast
no6in Unicode
builds, cast
no5yesyes
COleVariantBSTRnononoyes4yes4in MBCS
builds
in Unicode
builds
  • 1、即使 _bstr_t 提供了向非常量指針的轉換操作符,修改底層的緩沖區也會(huì )已引起GPF如果你溢出了緩沖區或者造成內存泄漏。
  • 2、_bstr_t 在內部用一個(gè) wchar_t* 來(lái)保存 BSTR,所以你可以使用 const wchar_t* 來(lái)訪(fǎng)問(wèn)BSTR。這是一個(gè)實(shí)現細節,你可以小心的使用它,將來(lái)這個(gè)細節也許會(huì )改變。
  • 3、如果數據不能轉換成BSTR會(huì )拋出一個(gè)異常。
  • 4、使用 ChangeType(),然后訪(fǎng)問(wèn) VARIANT 的 bstrVal 成員。在MFC中,如果數據轉換不成功將會(huì )拋出異常。
  • 5、這里沒(méi)有轉換 BSTR 函數,然而 AllocSysString() 返回一個(gè)新的BSTR。
  • 6、使用 GetBuffer() 方法,你可以暫時(shí)地得到一個(gè)非常量的TCHAR指針。

  • 作者簡(jiǎn)介

    Michael Dunn:
      
    Michael Dunn居住在陽(yáng)光城市洛杉磯。他是如此的喜歡這里的天氣以致于想一生都住在這里。他在4年級時(shí)開(kāi)始編程,那時(shí)用的電腦是Apple //e。1995年,在UCLA獲得數學(xué)學(xué)士學(xué)位,隨后在Symantec公司做QA工程師,在 Norton AntiVirus 組工作。他自學(xué)了 Windows 和 MFC 編程。1999-2000年,他設計并實(shí)現了 Norton AntiVirus的新界面。
      Michael 現在在 Napster(一個(gè)提供在線(xiàn)訂閱音樂(lè )服務(wù)的公司)做開(kāi)發(fā)工作,他還開(kāi)發(fā)了UltraBar,一個(gè)IE工具欄插件,它可以使網(wǎng)絡(luò )搜索更加容易,給了 googlebar 以沉重打擊;他還開(kāi)發(fā)了 CodeProject SearchBar;與人共同創(chuàng )建了 Zabersoft 公司,該公司在洛杉磯和丹麥的 Odense 都設有辦事處。
      他喜歡玩游戲。愛(ài)玩的游戲有 pinball, bike riding,偶爾還玩 PS, Dreamcasth 和 MAME 游戲。他因忘了自己曾經(jīng)學(xué)過(guò)的語(yǔ)言:法語(yǔ)、漢語(yǔ)、日語(yǔ)而感到悲哀。

    Nishant S(Nish)
      Nish是來(lái)自印度 Trivandrum,的 Microsoft Visual C++ MVP。他從1990年開(kāi)始編碼?,F在,Nish為作為合同雇員在家里為 CodeProject 工作?!  ?br>  他還寫(xiě)了一部浪漫戲劇《Summer Love and Some more Cricket》和一本編程書(shū)籍《Extending MFC applications with the .NET Framework》。他還管理者M(jìn)VP的一個(gè)網(wǎng)站http://www.voidnish.com/ 。在這個(gè)網(wǎng)站上,你可以看到他的很多關(guān)于編程方面的思想和文章。
    Nish 還計劃好旅游,他希望自一生中能夠到達地球上盡可能多的地方。
    本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
    打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
    猜你喜歡
    類(lèi)似文章
    VC常用數據類(lèi)型列表
    常用字符串長(cháng)度計算函數 - 游戲程序設計 - 云世界日志
    C 編程的 42 條建議(四)
    C++_數據類(lèi)型轉換技巧
    VC常用數據類(lèi)型使用轉換詳解
    BSTR、LPSTR和LPWSTR 等多種VC字符類(lèi)型分析及各種字符類(lèi)型轉換
    更多類(lèi)似文章 >>
    生活服務(wù)
    分享 收藏 導長(cháng)圖 關(guān)注 下載文章
    綁定賬號成功
    后續可登錄賬號暢享VIP特權!
    如果VIP功能使用有故障,
    可點(diǎn)擊這里聯(lián)系客服!

    聯(lián)系客服

    欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久