您的位置:首页 > 移动开发

C++字符串完全指南 第二部分-字符串封装类(String Wrapper Classes)

2008-05-31 09:33 615 查看
1.简介
因为C类型的字符串容易出错和难于管理,更不用提黑客经常利用这个进行缓冲区溢出攻击。现在存在很多字符的封装类。不幸的是,哪个类使用在哪种情况下不是很清楚,也不要把C类型的字符串直接转化成封装类。
这篇文章将覆盖字符串封装类包括Win32API,MFC,STL,WTL,和theVisualC++runtimelibrary。我将描述每个类的使用方法。怎么去构造对象,怎么从一种类型转化成另一个类。
为了更好的理解这篇文章,你必须理解不同字符的类型和编码,我在第一部分已经进行了介绍。

Rule#1ofstringclasses
直接转化是一个错误的想法,除非有明确的文档说明了这个情况。对一个字符进行转化对这个字符来说不会做任何改变,不要这么写:
voidSomeFunc(LPCWSTRwidestr);
main()
{
SomeFunc((LPCWSTR)"C://foo.txt");//WRONG!
}
这肯定会100%的失败,这个编译会通过,因为转化编译器不会进行类型检查,但是编译并不意味着代码正确。
在接下来的例子中,我将指出转化在什么情况下是没有问题的。

C-stylestringsandtypedefs
就像我第一部分所说的那样,WindowsAPIs是预先定义好的的,TCHARs,它是在编译的时候根据你是否定义了_MBCS或
_UNICODE
宏来选择是MBCS或Unicode字符。你可以通过第一部分得到TCHAR的全面描述,我将列出所有的字符类型定义。

Type

Meaning

WCHAR


Unicodecharacter(
wchar_t
)

TCHAR


MBCSorUnicodecharacter,dependingonpreprocessorsettings

LPSTR


stringof
char
(
char*
)

LPCSTR


constantstringof
char
(
constchar*
)

LPWSTR


stringof
WCHAR
(
WCHAR*
)

LPCWSTR


constantstringof
WCHAR
(
constWCHAR*
)

LPTSTR


stringof
TCHAR
(
TCHAR*
)

LPCTSTR


constantstringof
TCHAR
(
constTCHAR*
)

Herearethe
OLECHAR
-relatedtypedefsyouwillsee:

Type

Meaning

OLECHAR


Unicodecharacter(
wchar_t
)

LPOLESTR


stringof
OLECHAR
(
OLECHAR*
)

LPCOLESTR


constantstringof
OLECHAR
(
constOLECHAR*
)

TherearealsotwomacrosusedaroundstringandcharacterliteralssothatthesamecodecanbeusedforbothMBCSandUnicodebuilds:

Type

Meaning

_T(x)


Prepends
L
totheliteralinUnicodebuilds.

OLESTR(x)


Prepends
L
totheliteraltomakeitan
LPCOLESTR
.

Therearealsovariantson
_T
thatyoumightencounterindocumentationorsamplecode.Therearefourequivalentmacros--
TEXT
,
_TEXT
,
__TEXT
,and
__T
--thatalldothesamething.

StringsinCOM-BSTRandVARIANT

许多自动化和其它的COM接口用BSTR来代替strings,但是BSTR有一些缺陷,在这里我将介绍BSTR.
BSTR是Pascal类型(wherethelengthisstoredexplicitlyalongwiththedata)的字符串和C类型wherethestringlengthmustbecalculatedbylookingforaterminatingzerocharacter).的字符串的混合体。BSTR是一个Unicode类型的字符串,string预留了他它的长度,它也是以‘0’字符结尾的,这里有一个例子anexampleof"Bob"asa
BSTR
:

06000000


4200


6F00


6200


0000


--length--

B

o

b

EOS

注意字符串的长度(length)存储在前面。COM库知道传输多少个数据(Asasidenote,a
BSTR
canholdanyarbitraryblockofdata,notjustcharacters,andcancontainembeddedzerocharacters.However,forthepurposesofthisarticle,Iwillnotconsidersuchcases.)
A
BSTR
variableinC++isactuallyapointertothefirstcharacterofthestring.Infact,thetype
BSTR
isdefinedthisway:
typedefOLECHAR*BSTR;

Thisisveryunfortunate,becauseinrealitya
BSTR
isnotthesameasaUnicodestring.Thattypedefdefeatstype-checkingandallowsyoutofreelymix
LPOLESTR
sand
BSTR
s.Passinga
BSTR
toafunctionexpectinga
LPCOLESTR
(or
LPCWSTR
)issafe,howeverthereverseisnot.Therefore,it'simportanttobeawareoftheexacttypeofstringthatafunctionexpects,andpassthecorrecttypeofstring.
有许多APIs是用来操作BSTRs,但是最重要的两个函数是为BSTR分配和销毁空间,他们是SysAllocString()和
SysFreeString()
.SysAllocString()把一个Unicode字符串拷贝到一个BSTR变量中,
SysFreeString()是释放一个BSTR开辟的空间。


BSTRbstr=NULL;
bstr=SysAllocString(L"HiBob!");
if(NULL==bstr)
//outofmemoryerror
//Usebstrhere...
SysFreeString(bstr);
很自然的,BSTR封装类接管了内存管理。
另一个自动化的接口是VARIANT。它是用来在无类型的语言,比如JScript、VBScript传送数据的。一个
VARIANT可以包含许多的类型,比如long和IDispatch*。当一个VARIANT包含一个字符串,它就是一个BSTR.
对VARIANT我后面会讲的更详细。


Stringwrapperclasses

NowthatI'vecoveredthevarioustypesofstrings,I'lldemonstratethewrapper
classes.Foreachone,I'llshowhowtoconstructanobjectandhowtoconvertitt
oaC-stylestringpointer.TheC-stylepointerisoftennecessaryforanAPIcall,
ortoconstructanobjectofadifferentstringclass.Iwillnotcoverother
operatorstheclassesprovide,suchassortingorcomparison.
Onceagain,donotblindlycastobjectsunlessyouunderstandexactlywhatthe
resultingcodewilldo.

ClassesprovidedbytheCRT

_bstr_t

[code]_bstr_t
isacompletewrapperarounda
BSTR
,andinfactithidestheunderlying
BSTR
.Itprovidesvariousconstructors,aswellasoperatorstoaccessthe
underlyingC-stylestring.However,thereisnooperatortoaccessthe
BSTR
itself,
soa
_bstr_t
cannotbepassedasan
[out]
parametertoCOMmethods.Ifyouneeda
BSTR*
touseasaparameter,itiseasiertotheATLclass
CComBSTR
.
A
_bstr_t
canbepassedtoafunctionthattakesa
BSTR
,butonlybecauseof
threecoincidences.First,
_bstr_t
hasaconversionfunctionto
wchar_t*
;second,
wchar_t*
and
BSTR
appearthesametothecompilerbecauseofthedefinitionof
BSTR
;
andthird,the
wchar_t*
thata
_bstr_t
keepsinternallypointstoablockofmemory
thatfollowsthe
BSTR
format.Soeventhoughthereisnodocumentedconversionto
BSTR
,ithappenstowork.
//Constructing
_bstr_tbs1="charstring";//constructfromaLPCSTR
_bstr_tbs2=L"widecharstring";//constructfromaLPCWSTR
_bstr_tbs3=bs1;//copyfromanother_bstr_t
_variant_tv="Bob";
_bstr_tbs4=v;//constructfroma_variant_tthathasastring

//Extractingdata
LPCSTRpsz1=bs1;//automaticallyconvertstoMBCSstring
LPCSTRpsz2=(LPCSTR)bs1;//castOK,sameaspreviousline
LPCWSTRpwsz1=bs1;//returnstheinternalUnicodestring
LPCWSTRpwsz2=(LPCWSTR)bs1;//castOK,sameaspreviousline
BSTRbstr=bs1.copy();//copiesbs1,returnsitasaBSTR

//...
SysFreeString(bstr);

Notethat
_bstr_t
alsohasconversionoperatorsfor
char*
and
wchar_t*
.Thisis

aquestionabledesign,becauseeventhoughthosearenon-constantstringpointers,

youmustnotusethosepointerstomodifythebuffer,becausethatcouldbreakthe

internal
BSTR
structure.

_variant_t

_variant_t
isacompletewrapperarounda
VARIANT
,andprovidesmanyconstructors

andconversionfunctionstooperateonthemultitudeoftypesthata
VARIANT
can

contain.Iwillonlycoverthestring-relatedoperationshere.

//Constructing
_variant_tv1="charstring";//constructfromaLPCSTR
_variant_tv2=L"widecharstring";//constructfromaLPCWSTR
_bstr_tbs1="Bob";
_variant_tv3=bs1;//copyfroma_bstr_tobject

//Extractingdata
_bstr_tbs2=v1;//extractBSTRfromtheVARIANT
_bstr_tbs3=(_bstr_t)v1;//castOK,sameaspreviousline

Notethatthe
_variant_t
methodscanthrowexceptionsifthetypeconversioncannot

bemade,sobepreparedtocatch
_com_error
exceptions.

Alsonotethatthereisnodirectconversionfrom
_variant_t
toanMBCSstring.

Youwillneedtomakeaninterim
_bstr_t
variable,useanotherstringclassthat

providestheUnicodetoMBCSconversion,oruseanATLconversionmacro.

Unlike
_bstr_t
,a
_variant_t
canbepasseddirectlyasaparametertoaCOM

method.
_variant_t
derivesfromthe
VARIANT
type,sopassinga
_variant_t
inplace

ofa
VARIANT
isallowedbyC++languagerules.

STLclasses

STLjusthasonestringclass,
basic_string
.A
basic_string
managesazero-terminated

arrayofcharacters.Thecharactertypeisgiveninthe
basic_string
templateparameter.

Ingeneral,a
basic_string
shouldbetreatedasanopaqueobject.Youcangeta

read-onlypointertotheinternalbuffer,butanywriteoperationsmustuse

basic_string
operatorsandmethods.

Therearetwopredefinedspecializationsfor
basic_string
:
string
,which

contains
char
s,and
wstring
,whichcontains
wchar_t
s.Thereisnobuilt-in
TCHAR


specialization,butyoucanusetheonelistedbelow.

//Specializations
typedefbasic_string<TCHAR>tstring;//stringofTCHARs

//Constructing
stringstr="charstring";//constructfromaLPCSTR
wstringwstr=L"widecharstring";//constructfromaLPCWSTR
tstringtstr=_T("TCHARstring");//constructfromaLPCTSTR

//Extractingdata
LPCSTRpsz=str.c_str();//read-onlypointertostr'sbuffer
LPCWSTRpwsz=wstr.c_str();//read-onlypointertowstr'sbuffer
LPCTSTRptsz=tstr.c_str();//read-onlypointertotstr'sbuffer

Unlike
_bstr_t
,a
basic_string
cannotdirectlyconvertbetweencharactersets.

However,youcanpassthepointerreturnedby
c_str()
toanotherclass'sconstructor

iftheconstructoracceptsthecharactertype,forexample:

//Example,construct_bstr_tfrombasic_string
_bstr_tbs1=str.c_str();//constructa_bstr_tfromaLPCSTR
_bstr_tbs2=wstr.c_str();//constructa_bstr_tfromaLPCWSTR

ATLclasses

CComBSTR

CComBSTR
isATL's
BSTR
wrapper,andismoreusefulinsomesituationsthan
_bstr_t
.

Mostnotably,
CComBSTR
allowsaccesstotheunderlying
BSTR
,whichmeansyoucan

passa
CComBSTR
objecttoCOMmethods,andthe
CComBSTR
objectwillautomatically

managethe
BSTR
memoryforyou.Forexample,sayyouwantedtocallmethodsofthis

interface:

//Sampleinterface:


structIStuff:publicIUnknown
{
//BoilerplateCOMstuffomitted...
STDMETHOD(SetText)(BSTRbsText);
STDMETHOD(GetText)(BSTR*pbsText);
};

CComBSTR
hasan
operatorBSTR
method,soitcanbepasseddirectlyto
SetText()
.

Thereisalsoan
operator&
thatreturnsa
BSTR*
,soyoucanusethe
&
operatoron

a
CComBSTR
objecttopassittoafunctionthattakesa
BSTR*
.

CComBSTRbs1;
CComBSTRbs2="newtext";

pStuff->GetText(&bs1);//ok,takesaddressofinternalBSTR
pStuff->SetText(bs2);//ok,callsBSTRconverter
pStuff->SetText((BSTR)bs2);//castok,sameaspreviousline

CComBSTR
hassimilarconstructorsto
_bstr_t
,howeverthereisnobuilt-inconverter

toanMBCSstring.Forthat,youcanuseanATLconversionmacro.

//Constructing
CComBSTRbs1="charstring";//constructfromaLPCSTR
CComBSTRbs2=L"widecharstring";//constructfromaLPCWSTR
CComBSTRbs3=bs1;//copyfromanotherCComBSTR
CComBSTRbs4;

bs4.LoadString(IDS_SOME_STR);//loadstringfromstringtable

//Extractingdata
BSTRbstr1=bs1;//returnsinternalBSTR,butdon'tmodifyit!
BSTRbstr2=(BSTR)bs1;//castok,sameaspreviousline
BSTRbstr3=bs1.Copy();//copiesbs1,returnsitasaBSTR
BSTRbstr4;

bstr4=bs1.Detach();//bs1nolongermanagesitsBSTR

//...
SysFreeString(bstr3);
SysFreeString(bstr4);

Notethatinthelastexample,the
Detach()
methodisused.Aftercallingthat

method,the
CComBSTR
objectnolongermanagesits
BSTR
ortheassociatedmemory.

That'swhythe
SysFreeString()
callisnecessaryon
bstr4
.

Asafootnote,the
operator&
overridemeansyoucan'tuse
CComBSTR
directlyinsome

STLcollections,suchas
list
.Thecollectionsrequirethatthe
&
operatorreturn

apointertothecontainedclass,butapplying
&
toa
CComBSTR
returnsa
BSTR*
,not

a
CComBSTR*
.However,thereisanATLclasstoovercomethis,
CAdapt
.Forexample,

tomakealistof
CComBSTR
,declareitlikethis:

std::list<CAdapt<CComBSTR>>bstr_list;

CAdapt
providestheoperatorsrequiredbythecollection,butitisinvisibleto

yourcode;youcanuse
bstr_list
justasifitwerealistof
CComBSTR
.

CComVariant

CComVariant
isawrapperarounda
VARIANT
.However,unlike
_variant_t
,the
VARIANT


isnothidden,andinfactyouneedtoaccessthemembersofthe
VARIANT
directly.

CComVariant
providesmanyconstructorstooperateonthemultitudeoftypesthata

VARIANT
cancontain.Iwillonlycoverthestring-relatedoperationshere.

//Constructing
CComVariantv1="charstring";//constructfromaLPCSTR
CComVariantv2=L"widecharstring";//constructfromaLPCWSTR
CComBSTRbs1="BSTRbob";
CComVariantv3=(BSTR)bs1;//copyfromaBSTR

//Extractingdata
CComBSTRbs2=v1.bstrVal;//extractBSTRfromtheVARIANT

Unlike
_variant_t
,therearenoconversionoperatorstothevarious
VARIANT
types.

Asshownabove,youmustaccessthe
VARIANT
membersdirectlyandensurethatthe

VARIANT
holdsdataofthetypeyouexpect.Youcancallthe
ChangeType()
methodif

youneedtoconverta
CComVariant
'sdatatoa
BSTR
.

CComVariantv4=...//Initv4fromsomewhere
CComBSTRbs3;

if(SUCCEEDED(v4.ChangeType(VT_BSTR)))
bs3=v4.bstrVal;

Aswith
_variant_t
,thereisnodirectconversiontoanMBCSstring.Youwillneed

tomakeaninterim
_bstr_t
variable,useanotherstringclassthatprovidesthe

UnicodetoMBCSconversion,oruseanATLconversionmacro.

ATLconversionmacros

ATL'sstringconversionmacrosareaveryconvenientwaytoconvertbetweencharacter

encodings,andareespeciallyusefulinfunctioncalls.Theyarenamedaccordingto

thescheme
[sourcetype]2[newtype]
or
[sourcetype]2C[newtype]
.Macrosnamedwith

thesecondformconverttoaconstantpointer(thusthe"C"inthename).Thetype

abbreviationsare:

A:MBCSstring,
char*
(AforANSI)
W:Unicodestring,
wchar_t*
(Wforwide)
T:
TCHAR
string,
TCHAR*

OLE:
OLECHAR
string,
OLECHAR*
(inpractice,equivalenttoW)
BSTR:
BSTR
(usedasthedestinationtypeonly)

So,forexample,
W2A()
convertsaUnicodestringtoanMBCSstring,and
T2CW()


convertsa
TCHAR
stringtoaconstantUnicodestring.

Tousethemacros,firstincludetheatlconv.hheaderfile.Youcandothisevenin

non-ATLprojects,sincethatheaderfilehasnodependenciesonotherpartsofATL,

anddoesn'trequirea
_Module
globalvariable.Then,whenyouuseaconversion

macroinafunction,putthe
USES_CONVERSION
macroatthebeginningofthefunction.

Thisdefinessomelocalvariablesusedbythemacros.

Whenthedestinationtypeisanythingotherthan
BSTR
,theconvertedstringis

storedonthestack,soifyouwanttokeepthestringaroundforlongerthanthe

currentfunction,you'llneedtocopythestringintoanotherstringclass.When

thedestinationtypeis
BSTR
,thememoryisnotautomaticallyfreed,soyoumust

assignthereturnvaluetoa
BSTR
variableora
BSTR
wrapperclasstoavoidmemory

leaks.

Herearesomeexamplesshowingvariousconversionmacros:


Collapse
//Functionstakingvariousstrings:
voidFoo(LPCWSTRwstr);
voidBar(BSTRbstr);
//Functionsreturningstrings:
voidBaz(BSTR*pbstr);

#include<atlconv.h>

main()
{
usingstd::string;
USES_CONVERSION;//declarelocalsusedbytheATLmacros

//Example1:SendanMBCSstringtoFoo()
LPCSTRpsz1="Bob";
stringstr1="Bob";

Foo(A2CW(psz1));
Foo(A2CW(str1.c_str()));

//Example2:SendaMBCSandUnicodestringtoBar()
LPCSTRpsz2="Bob";
LPCWSTRwsz=L"Bob";
BSTRbs1;
CComBSTRbs2;

bs1=A2BSTR(psz2);//createaBSTR
bs2.Attach(W2BSTR(wsz));//ditto,assigntoaCComBSTR

Bar(bs1);
Bar(bs2);

SysFreeString(bs1);//freebs1memory
//Noneedtofreebs2sinceCComBSTRwilldoitforus.

//Example3:ConverttheBSTRreturnedbyBaz()
BSTRbs3=NULL;
stringstr2;

Baz(&bs3);//Baz()fillsinbs3

str2=W2CA(bs3);//converttoanMBCSstring
SysFreeString(bs3);//freebs3memory
}[/code]
Asyoucansee,themacrosareveryhandywhenpassingparameterstoafunctionif

youhaveastringinoneformatandthefunctiontakesadifferentformat.

MFCclasses

CString

AnMFC
CString
holds
TCHAR
s,sotheexactcharactertypedependsonthepreprocessor

symbolsyouhavedefined.Ingeneral,a
CString
islikeanSTL
string
,inthatyou

shouldtreatitasanopaqueobjectandmodifyitonlywith
CString
methods.One

niceadvantage
CString
hasovertheSTL
string
isthatithasconstructorsthat

acceptbothMBCSandUnicodestrings,andithasaconverterto
LPCTSTR
,soyou

canpassa
CString
objectdirectlytoafunctionthatacceptsan
LPCTSTR
;thereis

no
c_str()
methodyouhavetocall.

//Constructing
CStrings1="charstring";//constructfromaLPCSTR
CStrings2=L"widecharstring";//constructfromaLPCWSTR
CStrings3('',100);//pre-allocatea100-bytebuffer,fillwithspaces
CStrings4="Newwindowtext";

//YoucanpassaCStringinplaceofanLPCTSTR:
SetWindowText(hwndSomeWindow,s4);

//Or,equivalently,explicitlycasttheCString:
SetWindowText(hwndSomeWindow,(LPCTSTR)s4);

Youcanalsoloadastringfromyourstringtable.Thereisa
CString
constructor

thatwilldoit,alongwith
LoadString()
.The
Format()
methodcanoptionallyreada

formatstringfromthestringtableaswell.

//Constructing/loadingfromstringtable
CStrings5((LPCTSTR)IDS_SOME_STR);//loadfromstringtable
CStrings6,s7;

//Loadfromstringtable.
s6.LoadString(IDS_SOME_STR);

//Loadprintf-styleformatstringfromthestringtable:
s7.Format(IDS_SOME_FORMAT,"bob",nSomeStuff,...);

Thatfirstconstructorlooksodd,butthatisactuallythedocumentedthatwayto

loadastring.

Notethattheonlylegalcastyoucanapplytoa
CString
isacastto
LPCTSTR
.

Castingtoan
LPTSTR
(thatis,anon-
const
pointer)iswrong.Gettinginthehabit

ofcastinga
CString
toan
LPTSTR
willonlyhurtyourself,aswhenthecodedoes

breaklateron,youmightnotseewhy,becauseyouusedthesamecodeelsewhereand

ithappenedtowork.Thecorrectwaytogetanon-constpointertothebufferis

the
GetBuffer()
method.

Asanexampleofthecorrectusage,considerthecaseofsettingthetextofanitem

inalistcontrol:

CStringstr=_T("newtext");
LVITEMitem={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();//returncontrolofthebuffertostr

The
pszText
memberisan
LPTSTR
,anon-
const
pointer,thereforeyoucall
GetBuffer()


on
str
.Theparameterto
GetBuffer()
istheminimumlengthyouwant
CString
to

allocateforthebuffer.Ifforsomereasonyouwantedamodifiablebufferlarge

enoughtohold1K
TCHAR
s,youwouldcall
GetBuffer(1024)
.Passing0asthelength

justreturnsapointertothecurrentcontentsofthestring.

Thecrossed-outlineabovewillcompile,anditwillevenwork,inthiscase.But

thatdoesn'tmeanthecodeiscorrect.Byusingthenon-
const
cast,you'rebreaking

object-orientedencapsulationandassumingsomethingabouttheinternalimplementation

of
CString
.Ifyoumakeahabitofcastinglikethat,youwilleventuallyruninto

acasewherethecodebreaks,andyou'llwonderwhyitisn'tworking,becauseyou

usethesamecodeeverywhereelseandit(apparently)works.

Youknowhowpeoplearealwayscomplainingabouthowbuggysoftwareisthesedays?

Bugsarecausedbytheprogrammerswritingincorrectcode.Doyoureallywantto

writecodeyouknowiswrong,andthuscontributetotheperceptionthatallsoftware

isbuggy?Takethetimetolearnthecorrectwayofusinga
CString
andhaveyour

codework100%ofthetime.

CString
alsohastwofunctionsthatcreatea
BSTR
fromthe
CString
contents,

convertingtoUnicodeifnecessary.Theyare
AllocSysString()
and
SetSysString()
.

Asidefromthe
BSTR*
parameterthat
SetSysString()
takes,theyworkidentically.

//ConvertingtoBSTR
CStrings5="Bob!";
BSTRbs1=NULL,bs2=NULL;

bs1=s5.AllocSysString();
s5.SetSysString(&bs2);

//...
SysFreeString(bs1);
SysFreeString(bs2);

COleVariant

COleVariant
isprettysimilarto
CComVariant
.
COleVariant
derivesfrom
VARIANT
,so

itcanbepassedtoafunctionthattakesa
VARIANT
.However,unlike
CComVariant
,

COleVariant
onlyhasan
LPCTSTR
constructor.Therearenotseparateconstructors

for
LPCSTR
and
LPCWSTR
.Inmostcasesthisisnotaproblem,sinceyourstrings

willlikelybe
LPCTSTR
sanyway,butitisapointtobeawareof.
COleVariant
also

hasaconstructorthatacceptsa
CString
.

//Constructing
CStrings1=_T("tcharstring");
COleVariantv1=_T("Bob");//constructfromanLPCTSTR
COleVariantv2=s1;//copyfromaCString

Aswith
CComVariant
,youmustaccessthe
VARIANT
membersdirectly,usingthe

ChangeType()
methodifnecessarytoconvertthe
VARIANT
toastring.However,

COleVariant::ChangeType()
throwsanexceptionifitfails,insteadofreturninga

failure
HRESULT
code.

//Extractingdata
COleVariantv3=...;//fillinv3fromsomewhere
BSTRbs=NULL;

try
{
v3.ChangeType(VT_BSTR);
bs=v3.bstrVal;
}
catch(COleException*e)
{
//error,couldn'tconvert
}

SysFreeString(bs);

WTLclasses

CString

WTL's
CString
behavesexactlylikeMFC's
CString
,sorefertothedescriptionofthe

MFC
CString
above.

CLRandVC7classes

System::String
isthe.NETclassforhandlingstrings.Internally,a
String
object

holdsanimmutablesequenceofcharacters.Any
String
methodthatsupposedly

manipulatesthe
String
objectactuallyreturnsanew
String
object,becausethe

original
String
isimmutable.Apeculiarityof
String
sisthatifyouhavemore

thanone
String
containingthesameseries,ofcharactersallofthemactually

referthesameobject.TheManagedExtensionstoC++haveanewstringliteral

prefix
S
,whichisusedtorepresentamanagedstringliteral.

//Constructing
String*ms=S"Thisisanicemanagedstring";

Youcanconstructa
String
objectbypassinganunmanagedstring,butthisis

slightlylessefficientthanwhenyouconstructa
String
objectbypassinga

managedstring.Thisisbecauseallinstancesofidentical
S
prefixedstrings

representthesameobject,butthisisnottrueforunmanagedstrings.Thefollowing

codewillmakethisclear:

String*ms1=S"thisisnice";
String*ms2=S"thisisnice";
String*ms3=L"thisisnice";

Console::WriteLine(ms1==ms2);//printstrue
Console::WriteLine(ms1==ms3);//printsfalse

Therightwaytocomparestringsthatmaynothavebeencreatedusing
S
prefixed

stringsistousethe
String::CompareTo()
methodasshownbelow:

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

Boththeabovelineswillprint0,whichmeansthestringsareequal.

Convertingbetweena
String
andtheMFC7
CString
iseasy.
CString
hasaconverter

to
LPCTSTR
and
String
hastwoconstructorsthattakea
char*
and
wchar_t*
,

thereforeyoucanpassa
CString
straighttoa
String
constructor.

CStrings1("helloworld");
String*s2(s1);//copyfromaCString

Convertingtheotherwayworkssimilarly:

String*s1=S"Threecats";
CStrings2(s1);

Thismightpuzzleyouabit,butitworksbecausestartingwithVS.NET,
CString
has

aconstructorthatacceptsa
String
object:

CStringT(System::String*pString);

Forsomespeedymanipulations,youmightsometimeswanttoaccesstheunderlying

string:

String*s1=S"Threecats";

Console::WriteLine(s1);

const__wchar_t__pin*pstr=PtrToStringChars(s1);

for(inti=0;i<wcslen(pstr);i++)
(*const_cast<__wchar_t*>(pstr+i))++;

Console::WriteLine(s1);

PtrToStringChars()
returnsa
const__wchar_t*
totheunderlyingstringwhichweneed

topindownasotherwisethegarbagecollectormightmovethestringinmemorywhile

wearemanipulatingitscontents.

Usingstringclasseswithprintf-styleformattingfunctions

Youmustpaycarefulattentionwhenusingstringwrapperclasseswith
printf()
or

anyfunctionthatworkstheway
printf()
does.Thisincludes
sprintf()
andits

variants,aswellasthe
TRACE
and
ATLTRACE
macros.Becausethereisnotype-checking

doneontheadditionalparameterstothefunctions,youmustbecarefultoonlypassaC-stylestringpointer,notacompletestringobject.

Soforexample,topassastringina
_bstr_t
to
ATLTRACE()
,youmustexplicitly

writethe
(LPCSTR)
or
(LPCWSTR)
cast:

_bstr_tbs=L"Bob!";

ATLTRACE("Thestringis:%sinline%d/n",(LPCSTR)bs,nLine);

Ifyouforgetthecastandpasstheentire
_bstr_t
object,thetracemessagewill

displaymeaninglessoutput,sincewhatwillbepushedonthestackiswhatever

internaldatathe
_bstr_t
variablekeeps.

Summaryofalltheclasses

Theusualwayofconvertingbetweentwostringclassesistotakethesourcestring,convertittoaC-stylestringpointer,andthenpassthepointertoaconstructorinthedestinationtype.SohereisachartshowinghowtoconvertastringtoaC-stylepointer,andwhichclassescanbeconstructedfromC-stylepointers.

Class

string
type

convert
to
char*
?

convertto
constchar*
?

convertto
wchar_t*
?

convertto
constwchar_t*
?

convert
to
BSTR
?

construct
from
char*
?

construct
from
wchar_t*
?

_bstr_t


BSTR


yes,cast1

yes,cast

yes,cast1

yes,cast

yes2

yes

yes

_variant_t


BSTR


no

no

no

castto
_bstr_t
3

castto
_bstr_t
3

yes

yes

string


MBCS

no

yes,
c_str()

method

no

no

no

yes

no

wstring


Unicode

no

no

no

yes,
c_str()

method

no

no

yes

CComBSTR


BSTR


no

no

no

yes,cast
to
BSTR


yes,cast

yes

yes

CComVariant


BSTR


no

no

no

yes4

yes4

yes

yes

CString


TCHAR


no6

inMBCS
builds,cast

no6

inUnicode
builds,cast

no5

yes

yes

COleVariant


BSTR


no

no

no

yes4

yes4

inMBCSbuilds

inUnicodebuilds

1Eventhough
_bstr_t
providesconversionoperatorstonon-
const
pointers,modifyingtheunderlyingbuffermaycauseaGPFifyouoverrunthebuffer,oraleakwhenthe
BSTR
memoryisfreed.
2A
_bstr_t
holdsa
BSTR
internallyina
wchar_t*
variable,soyoucanusethe
constwchar_t*
convertertoretrievethe
BSTR
.Thisisanimplementationdetail,sousethiswithcaution,asitmaychangeinthefuture.
3Thiswillthrowanexceptionifthedatacannotbeconvertedtoa
BSTR
.
4Use
ChangeType()
thenaccessthe
bstrVal
memberofthe
VARIANT
.InMFC,thiswillthrowanexceptionifthedatacannotbeconverted.
5Thereisno
BSTR
conversionfunction,howeverthe
AllocSysString()
methodreturnsanew
BSTR
.
6Youcantemporarilygetanon-const
TCHAR
pointerusingthe
GetBuffer()
method.

http://www.codeproject.com/KB/string/cppstringguide2.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: