Você está na página 1de 88

Tiago Barros 2002

ObralicenciadasoblicenaCreativeCommonsAtribuioNoComercial Compartilhamentopelamesmalicena2.5Brasil

ndiceAnaltico

ndice Analtico

CAPTULOI ....................................................................................................................................................... 7

EngenhariadeSoftwareEstruturada.................................................................................7 EngenhariadeSoftwareEstruturada:ousodefunes...................................................8 OC++bsico..........................................................................................................................8


Tipos:estruturas,uniesetiposenumerados.......................................................................................................8 Declarandoarrays.................................................................................................................................................8 Definindonovostipos...........................................................................................................................................8 Modificadoresdetipos.......................................................................................................................................10 Interna...........................................................................................................................................................10 Conversesdetipos............................................................................................................................................11 LaoseCondicionais..........................................................................................................................................12 Ponteiros.............................................................................................................................................................14 Umabrevediscussosobreendereosdememria............................................................................................14 Comodeclararponteiros.....................................................................................................................................14 Utilizandoponteiros...........................................................................................................................................14 Criandovariveisemtempodeexecuo:osoperadoresnewedelete.............................................................16 Ponteirosparatiposderivados............................................................................................................................17 Ponteirosearrays................................................................................................................................................17 Usandonewedeletecomarrays........................................................................................................................18 Aritmticadeponteiros......................................................................................................................................18 Ponteiroseconst.................................................................................................................................................18 Funes...............................................................................................................................................................19 Definindofunes...............................................................................................................................................19 Argumentosetiposderetornodefunes.........................................................................................................20 Ponteirosparafunes........................................................................................................................................21 Funesinline...................................................................................................................................................22 Umpoucomaissobreargumentos......................................................................................................................22 Sobrecargadefunes........................................................................................................................................24

Seoprtica:definindonossoprojeto.............................................................................25
CAPTULOII ................................................................................................................................................... 27

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoG.Barros

EngenhariadeSoftwareBaseadaemObjetos..................................................................27 Engenhariadesoftwarebaseadaemobjetos....................................................................28
Modularidade,coesoeacoplamento.................................................................................................................28 InformationHidding...........................................................................................................................................28 SuportemodularidadeemC++........................................................................................................................28 Suportereusabilidade:Modelosdefuno......................................................................................................30

Seoprtica:estruturandoonossoprojetoemmdulos...............................................32
CAPTULOIII ................................................................................................................................................. 33

EngenhariadeSoftwareBaseadaemClasses...................................................................33 EngenhariadeSoftwareBaseadaemClasses...................................................................34
ClassesemC++..................................................................................................................................................34 Classes:organizaoemarquivos......................................................................................................................36 Modificadoresdemtodos..................................................................................................................................37 Comocriarmembrosestticos...........................................................................................................................38 Oponteirothis....................................................................................................................................................38 Sobrecargademtodoseconstrutores................................................................................................................39 Construtoresdecpia.........................................................................................................................................39 Funes,mtodoseclassesfriend......................................................................................................................40 Conversesentreobjetos....................................................................................................................................42 Sobrecargadeoperadores...................................................................................................................................43 Modelosdeclasses.............................................................................................................................................46

Seoprtica:Criandoclassesparaojogo.......................................................................49
CAPTULOIV .................................................................................................................................................. 51

EngenhariadeSoftwareOrientadaaObjetos..................................................................51 EngenhariadeSoftwareOrientadaaObjetos..................................................................52
HeranaemC++.................................................................................................................................................52 Overloaddeconstrutores,destrutoresemtodos...............................................................................................52 Mtodosvirtuais:dynamicbinding....................................................................................................................53 Classesabstratas.................................................................................................................................................55 Heranamltipla.................................................................................................................................................56 Excees.............................................................................................................................................................58

Seoprtica:Utilizandoherana.....................................................................................61
CAPTULOV ................................................................................................................................................... 62

ndiceAnaltico

RecursosavanadosdoC++:RTTIeSTL......................................................................62 ARTTI(runtimetypeinformation)..................................................................................63
Ooperadordynamic_cast...................................................................................................................................63 Utilizandoooperadortypeideaclassetype_info..............................................................................................63

ASTL(standardtemplatelibrary)...................................................................................65
ContineresdaSTL............................................................................................................................................65 Iteradores............................................................................................................................................................81 AlgoritmosdaSTL.............................................................................................................................................82 Objetosfuno....................................................................................................................................................87

Captulo I

Engenharia de Software Estruturada

CaptuloIEngenhariadeSoftwareEstruturada

Engenharia de Software Estruturada: o uso de funes


Nosprimrdiosdaprogramao,osprogramaseramcriadosseguindoumanicaseqncia,ouseja,tnhamos programascompletosescritossemnenhumaestruturao.Aidiadefuno,cdigoquepodeserchamado vriasvezesemdiferentespartesdoprogramaecomdiferentesparmetros,trouxeumagrandeestruturao programao. Neste captulo veremos como utilizar funes, e na seo prtica, como estruturar nosso programaemfunes.Paraisto,comearemoscomumavisogeraldobsicodeC++,paraquetenhamoso suportenecessrioparautilizarasfunes.

O C++ bsico
Tipos: estruturas, unies e tipos enumerados
Comovoc j devesaber,quandonos referimos atipo,estamosfalandodotipodavarivel (poro de memriautilizadaparaguardardados).Ostiposdiferemnoformatocomoosdadossoarmazenadosena quantidade de memria utilizada. Tambm diferem na semntica, pois embora possam ter a mesma quantidade de memria, dois tipos podem guardar informaes de significado diferente. O C++ uma linguagemfortementetipada,oquesignificaqueasoperaessobrevariveissorealizadasapenasentre variveisdomesmotipo,oudetiposcompatveis.AlinguagemC++definevriostiposprprios,chamados tiposbsicos.Suascaractersticas,quevoc j deveconhecer,podemserencontradasnoApndiceA,de formaquenoprolongareiaquiumadiscussosobredeclaraoeutilizaodetiposbsicos.

Declarando arrays
Arraynadamaisdoqueumconjuntodevariveisdomesmotipoquesoacessadaspelomesmonomeeum ndice. Paradeclararumarraydechar,porexemplo,fazemos: char array_de_char[20]; Ovalorentreparntesesaquantidadedeposiesqueoarraypossui,ouseja,array_de_charpossui20 variveis do tipo char. Veremos a importncia dos arrays e como utilizar arrays multidimensionais e ponteiroscomarraysmaisadiante,nestecaptulo.

Definindo novos tipos


Almdostiposdedadossimplescomoint,float,double,char,...;podemosdefinirosnossoprpriostipos dedados.Estestipossodefinidosatravsdaspalavraschave struct,unioneenum(eposteriormente,como veremos,class). Estruturas As estruturas de C++ funcionam como tipos compostos, em que se pode guardar diversas informaes agrupadasemummesmonome.Porexemplo,paradefinirotipocompostobola,utilizamos structdeacordo comasintaxeabaixo: struct TBall { int x; int y;

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

};

int radius; TColor color;

Abolaquedefinimostem,portanto,umaposio(x,y),umraioeumacor.Secriarmosumavariveldotipo bola,queacabamosdedefinir,podemosacessarascaractersticasdaboladaseguinteforma: TBall bola; bola.x = 10; bola.y = 15; bola.radius = 5; bola.color = clBlue; Note,queTColorno umtipodedadossimples,deformaquepodemoscriartiposdedadoscompostosa partirdeoutrostiposcompostostambm. Unies Uma unio um tipo composto parecido com uma estrutura. A diferena que na unio, os diversos membroscompartilhamamesma readememria,ouseja,alterandoummembrodaunio,narealidade estamos alterando todos. As unies so utilizadas quando queremos acessar uma mesma informao de diversasformas,sobreaticadediversostiposdedados,ex: union TCharInt { char c; short i; }; int main() { TCharInt var; var.c = A; cout << O codigo ASCII da letra A e << var.i; cin.get(); } return 0;

Nocdigoacima,nsatribumosumaconstantedotipo charuniovar.Posteriormente,acessamosaunio varatravsdoseumembroi,dotiposhort int.ComoaletraA representadainternamenteatravsdoseu cdigo numrico, quando acessamos a varivel como um tipo short int, teremos como retorno o valor numrico(docdigoASCII)daletraA.Portanto,oexemploacimaexibir: O codigo ASCII da letra A e 65 Tipos enumerados OstiposdedadosenumeradossoutilizadospararepresentartiposconceituaisquenoestopresentesnoC+ +padro.Porexemplo,pararepresentarotipodedadoscor,quepodeassumirosvaloresvermelho,verde, azul,amarelo,ciano,magenta,brancoepreto;poderamosutilizarumtipodedadosenumerado:

CaptuloIEngenhariadeSoftwareEstruturada enum TColor {clRed, clGreen, clBlue, clYellow, clCian, clMagenta, clWhite, clBlack }; Desta forma, as variveis do tipo TColor s aceitariam um dos valores acima, que, internamente esto representadospornmeros,masnocdigotmumasemnticaquebastantetilparaquemforutilizar.

Modificadores de tipos
EmC++,podemosmodificaraformacomoasvariveissodeclaradasealocadas,seuescopoeasualigao (capacidade de um item ser usado em diferentes arquivos de um mesmo programa). Isto feito com a utilizaodosmodificadoresdetipo.Paraentendermelhoroseufuncionamento,veremosalgunsconceitos bsicosnecessrios,antesdefalardosmodificadoresdetipospropriamenteditos. Escopo VariveisemC++podemterescopolocal(oudebloco)ouglobal(oudearquivo).Variveisglobaisficam disponveisatodoocdigodoarquivo,enquantoasvariveislocaisestodisponveisapenasdentrodobloco emqueforamcriadasenosblocosinternosaele. Classes de armazenamento Amemriadearmazenamento(espaoreservado svariveis)deumprogramaemC++ divididaemtrs classes: Armazenamento automtico: onde as variveis de um bloco so alocadas e armazenadas quando o programaentranobloco.Seuescopolocal. Armazenamento esttico: rea dearmazenamento persistente. Os dados comarmazenamento esttico estodisponveisdurantetodaaexecuodoprograma.Istosignificaqueosdadosestticosnoso reinicializadosacadavezqueumafunochamada,comoocorrecomoarmazenamentoautomtico. Armazenamentolivre: readealocaodememriaemtempodeexecuo.Todavarivelalocadaem tempodeexecuo armazenadanesta rea. desumaimportnciaqueasvariveiscriadasnesta rea sejamdesalocadassemprequenoforemmaisserutilizadas.

Ligao Aligao(lincagem)sereferecapacidadedeumitemserutilizadoemdiversosarquivosdeumprograma. Variveisexternas(declaradasforadequalquerfuno)possuemtambmligaoexterna,oquesignificaque elasficamdisponveisaqualquerarquivodomesmoprograma.J asvariveisdeligaointernas esto disponveisnoarquivoemqueforamcriadas. Osconceitosvistosacimaestorelacionadosdeformanosistemtica,sendo svezesdifcildeseentender claramente. Portanto, abaixo segue uma lista das possveis associaes entre classes de armazenamento, escopoeligao: Tipodavarivel Variveisautomticas Variveisexternas Variveisexternasestticas Variveisexternasconstantes Variveisestticas Formadedeclarao Declaradasdentrodeumbloco Declaradasforadequalquerfuno Variveisexternasdeclaradascoma palavrachavestatic Variveisexternasdeclaradascoma palavrachaveconst Variveisautomticasdeclaradascoma palavrachavestatic Escopo Local Global Global Global Local Ligao Interna Externa Interna Interna Interna

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Depoisdeentendidosestesconceitos,vamosaosmodificadorespropriamenteditos. Modificadores: static:utilizadoparadeclararvariveisnaclassedearmazenamentoesttico. const:utilizadoparadeclararconstantes,que,obviamente,nopodemteroseucontedoalterado. extern: utilizadoparaindicarqueestamosutilizandoumavarivelexterna,quefoideclaradaemoutro arquivo. register: utilizadoparapediraocompiladorquearmazeneavarivelemumregistradordaCPU.Isto aceleraoacessovarivel,masnodeveserutilizadoparatodasasvariveispoisoscomputadorespossuem geralmenteregistradoresde32bits(emalgunscomputadores,64bits),que umtamanhomenordoque algunstiposcomodouble,eemnmerolimitado. volatile:indicaqueumvalordeumavarivelpodeseralteradoporfatoresexternosaocdigodoprograma, como,porexemplo,umavarivel queapontepara oendereo dorelgiodosistema,eque,portanto, atualizada pelo hardware. Variveis em programas multithreaded1 que so alteradas e lidas em threads diferentestambmdevemserdeclaradascomovolatile. mutable:indicaqueummembrodeumaestrutura(ouclasse)podeseralteradomesmoquefaapartedeuma variveldeclaradacomoconstante.

Converses de tipos
Quasesempre,emumprograma,existeanecessidadedesefazeraconversoentretiposdedadosparaquese possarealizaroperaescomvariveisdetiposdiferentes.Aconversodetipos(outypecasting)podeser realizadadaformaimplcitaouexplcita. Cast implcito Ocorre quando fazemos converso entre variveis de tipos compatveis, onde no h a necessidade de utilizaodepalavraschaveparainformaraconversoaocompilador.Ex: short int numShort = 1234; long int numLong = 314153256; long int result; result = numShort + numLong; Cast explcito Utilizamos o cast explcito quando queremos informar ao compilador que no estamos fazendo uma conversoindesejada,etambmquandoostiposnosocompatveismasaconverso necessria.Abaixo seguemasformasdefazerocastexplcitoemC++: (tipo):conversoexplcitadetiposestiloC.consideradaantigaeobsoleta. static_cast<tipo>(expresso): utilizadoquandoqueremosfazerumcastemtempodecompilao,ou seja,nohverificaodetiposemtempodeexecuo.Ex: int sum; int num = 10; float pi = 3.14159;
1

Programacomvriaslinhasdeexecuo,chamadasthreads,querodamemparalelo,naticadoprograma. 10

CaptuloIEngenhariadeSoftwareEstruturada sum = static_cast <int> (pi) + num; const_cast<tipo>(expressoconstante): utilizadopararetiraraconstnciadeexpresses.Noexemplo abaixo,podemosdesconsiderarofatoqueconst_ptr umponteiroconstantequandoatribumoseleaum ponteironormal(nosepreocupe,veremosousodeponteirosmaisadiante): char * ptr; const char * const_ptr; . . . ptr = const_cast <char *> (const_ptr); reinterpret_cast<tipo>(expresso):oreinterpret_cast aformamaispoderosadeconversodetipos.Ele fora a reinterpretao dos bits da expresso, de forma que os valores reais dos bits de um valor so utilizados.Devidoaoseupoder,seuusobastanteperigoso,poisfazerumreinterpret_castdeumfloatpara umint,porexemplo,poderiaresultaremumvalorinteirocompletamentesemsentido.Umexemplodeusodo reinterpret_castpodeservistoaseguir: pointer = reinterpret_cast <int *> (0xB0000000); Esteexemplofazcomqueoponteiropointeraponteparaoendereodememria0xB0000000. Seno utilizssemos o reinterpret_cast, o exemplo acima no compilaria, pois o compilador no considera a conversodotipounsignedlongparaint*algoquesepossafazerimplicitamente. dynamic_cast<tipo>(expresso):utilizadoparafazerconversesemtempodeexecuo.Elefazparteda RTTI(runtimetypeidentificationidentificaodetiposemtempodeexecuo)eser vistocomdetalhes noCaptuloV.

Laos e Condicionais
Elementosessenciaisemlinguagensdeprogramao,asinstruescondicionais(ouinstruesdeseleo,de acordocomaespecificaodoANSI/ISSOC++)eas instruesdeiterao seroabordadasnestaseo, bemcomoasinstruesdecontroledefluxo(break,continue,exiteabort). A instruo if utilizada para testar expresses e tomar decises. Se a expresso entre parnteses for avaliada como verdadeiraoudiferentedezero,seublocodeinstruescorrespondenteser executado.Possuiumaclusula opcional,else,queexecutaumblocodeinstruescasoaexpressoentreparntesessejaavaliadacomofalsa. Podemos ter vrios blocos ifelse aninhados, por exemplo para testar uma varivel sucessivamente, at encontrarmosumacorrespondncia.Asintaxedainstruoif: if (expresso) { bloco de instrues que sero executadas caso expresso seja avaliada como verdadeira; } else { bloco de instrues que sero executadas caso expresso seja

11

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

avaliada como falsa; } A instruo switch Umaalternativaparaautilizaode ifelse aninhados ainstruo switch.Estainstruo utilizadapara desviosmltiplos,deumaformamaissinttica.Asintaxedoswitch: switch (expresso) { case valor1: instruo1; [break;] case valor2: instruo2; [break;] case valor3: instruo3; [break;] . . . default: instruo_padro; } Casoainstruobreaknosejautilizada,oprogramacontinuar executandoasinstruesdoprximo case atquehajaumbreakouqueacabeoblocoswitch. Os laos while e do-while Umlaowhileexecutaseublocodeinstruesenquantoasuaexpressoforavaliadacomoverdadeira(ou diferentedezero).Possuiasseguintessintaxes: while (expresso) { instrues; } ou do {

instrues; } while (expresso); Adiferena, quenolaowhilepuro,aexpresso avaliadaantesdeexecutarasinstrues,enquantono lao dowhile asinstrues soexecutadas eaexpresso avaliadanofinal(portantoasinstrues so executadaspelomenosumavez). O lao for

12

CaptuloIEngenhariadeSoftwareEstruturada Olaofor utilizadoquandodesejamosutilizarumndicenumrico,quesejaincrementado/decrementadoa cadaiterao.Suasintaxe: for (inicializao; expresso_de_teste; expresso_de_iterao) { instrues; } A inicializao executadaantesdecomearemasiteraesdolao. geralmenteondeinicializamosas variveisde ndicequeseroutilizadasnolao.Acadaiterao,aexpresso_de_teste avaliadaeolao encerrado quando ela se torna falsa. Aps cada execuo do corpo do lao, a expresso_de_iterao executada.Essaexpresso,geralmente,umincremento/decrementoda(s)varivel(is)dendice. Instrues de controle de fluxo break:utilizadaparaterminaraexecuodeumlaooudeumblocoswitch. continue: faz com que a execuo do programa pule para a prxima iterao de um lao, ou seja, as instruesentrecontinueeofimdocorpodolaonosoexecutadas. goto label: transfere o fluxo do programa para a instruo seguinte a label. Seu uso extremamente desaconselhado,poistornaofluxodoprogramabastantedifcildeacompanharedepurar.Sempreexisteuma formadeescreverumprogramasemgoto.Portantonouseestainstruo. exit:terminaaexecuodoprograma.Podeserchamadadequalquerfuno,noapenasdafunomain. abort:terminaimediatamenteaexecuodoprograma,semexecutarasinstruesdeencerramentodetempo deexecuodoC++(comochamarosdestrutoresdosobjetosglobaisporexemplo).

Ponteiros
AsvariveisponteirosoumdosmaioresrecursosdeC++peloseupoder,mastambmumdosmaiores causadoresdebugseoterrordealgunsprogramadores.Nestasessoveremosqueosponteirossoumdos nossosmaioresaliadosetambmveremoscomonocairnassuasarmadilhas.

Uma breve discusso sobre endereos de memria


TodasasvariveisdeC++possuemum nomeeum contedo,eestoarmazenadasemalgumaposiode memria.Nonossoprogramautilizamosessesnomesparareferenciaroscontedosdasvariveis.Umaoutra formadereferenciarumaposiodememria atravsdoseuendereodireto.Paraobteroendereode elementosdememriaoC++possuiooperador&,chamadooperadorendereooureferncia.Destaforma, podemosdeclararvariveisqueguardememvezdevaloresdetipos,endereosdememria.Istonospermite criar variveis em tempo de execuo e guardar o seu endereo nestas variveis especiais, chamadas ponteiros.Veremoscomodeclararemanipularponteirosnasseesaseguir.

Como declarar ponteiros


Apesardeutilizaremespaosdememriadomesmotamanho,poistodososponteirosguardamendereosde memria,cadaponteiroprecisaserdomesmotipododadoqueeleaponta,ousejaumponteiroparainteiros deveserdotipo int,enquantoumponteiropara double deveserdotipo double.Paradeclararponteiros, utilizamosumasterisco,*,apsonomedotipo,daseguinteforma: int *ponteiro_para_int; double *ponteiro_para_double;

13

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Utilizando ponteiros
Parautilizarmososponteirosparaapontarparaumavarivel,utilizamosooperadorendereo,&: int um_inteiro = 10; double um_double = 3.14159; ponteiro_para_int = &um_inteiro; ponteiro_para_double = &um_double; Paraacessarocontedodasvariveisapontadaspeloponteiro,utilizamosooperador desreferncia,*,que tambmumasterisco: cout << O valor de um_inteiro : << *ponteiro_para_int; cout << O valor de um_double : << *ponteiro_para_double; Quenosdarcomosada: O valor de um_inteiro : 10 O valor de um_double : 3.14159 Ooperadordesrefernciafazcomque,emvezdeexibirocontedodavarivelponteiro,queoendereode um_inteiro, utilize esse contedo como endereo e exiba o contedo deste endereo, que 10. Complicado?No,muitomaissimplesdoqueseimagina.Vejamosalgunsexemplosdeusodosoperadores &e*,eoqueaconteceriaemcadacaso: Exemplo1: cout << O valor de um_inteiro : << &um_inteiro; Apesardepassarpelocompilador,esteexemploestariasemanticamenteincorreto,poisoqueseriaexibidoo endereodeum_inteiroenooseuvalor. Exemplo2: cout << O valor de um_inteiro : << *um_inteiro; Esteexemplocausaerrodecompilaopoisavarivelum_inteiro,apesardeteromesmotamanhodeum ponteiroeguardarumvalornumrico,nofoideclaradacomoponteiro,enopodeterseucontedoutilizado paraenderearmemria. Exemplo3: cout << O valor de um_inteiro : << &ponteiro_para_int; Nesteexemplo,estaramosexibindooendereodeponteiro_para_int,enoocontedodoendereo queeleaponta.Seestivssemosatribuindo&ponteiro_para_intparaumavarivel,comoestavarivel deveriaserdeclarada?Corretoserespondeu:int**ponteiro_duplo;Poisoendereodeumponteiro deveserguardadoemumponteiroparaponteiro. Exemplo4: cout << O valor de um_inteiro : << *ponteiro_para_int;

14

CaptuloIEngenhariadeSoftwareEstruturada

Estaseriaaformacorretadeutilizaroponteiro,eoqueseriaexibidoseriaovalorguardadonoendereo guardadonoponteiro. Comoveremosmaisadiante,almdostiposbsicos,podemosutilizarponteirosparatiposcompostos,objetos efunes.

Criando variveis em tempo de execuo: os operadores new e delete


Atagora,todaamemriaquensutilizamoseraalocadaatravsdadeclaraodevariveis,oquesignifica queestvamosinformandoaoC++oquantodememriaqueonossoprogramairiautilizar.Comovimos anteriormente, a memria do nosso programa est dividida em trs classes de armazenamento: o armazenamentoautomtico(paravariveisdeclaradaslocalmente),oarmazenamentoesttico(paravariveis declaradascomstaticeparaasvariveisglobais)eoarmazenamentolivre(paraasvariveisdeclaradasem tempodeexecuo).Portanto,podemosalocareliberarmemriadareadearmazenamentolivre,emtempo deexecuo,oquenospermiteumamaioreficincianogerenciamentodememria.Isto feitoatravsdos operadoresnewedelete. Ooperadornewretornaumponteiroparaotipoespecificado,deformaque,sequisermoscriaruminteiroem tempodeexecuo,devemosprocederdaseguinteforma: int *ponteiro_para_int; ponteiro_para_int = new int; Agoravoc entendeousodeponteiros,poisnofezmuitosentidooseuusocomonosexemplosdaseo utilizandoponteiros,certo? Asvariveisdareadearmazenamentoautomticosodesalocadaslogoqueoprogramasaidoseuescopo, automaticamente (da o nome armazenamento automtico). Isto no ocorre com as variveis da rea de armazenamento livre. Embora possam estar sendo referenciadas por ponteiros declarados localmente (e portanto, localizados na rea de armazenamento automtico), todas as variveis criadas dinamicamente continuam aexistirdurante todaaexecuo doprograma, ouat quesejam desalocadas explicitamente. Vejamosummauusodealocaodinmica: for (int i=0; i < 1000; i++) { double *pointer; pointer = new double; pointer = i * 3.14159; } Nesteexemplo,avarivel pointer declaradadentrodocorpodo for,eporisso criadana reade armazenamento automtico.Ento,noinciodaexecuo decada iterao, alocada memriapara esta varivel.Depois,comooperadornew, alocadamemria(destavezna readearmazenamentolivre)para umavariveldotipodouble,eoendereo guardadoempointer,deformaapoderutilizaresta reade memria. No fim da execuo da iterao, a varivel pointer desalocada. Ento voc deve estar se perguntando:oqueacontececomareaalocadapelooperador new?Exatamente!Comonoexistenenhum ponteiroquereferenciea reaalocadaecomoelanofoiliberada,ficar ocupandoespaoat ofinaldo programa. Destaforma, aofinal destelao,teremos 1000*8bytes dememria(otamanhodo double geralmente8bytes)queestalocadamasnopoderserutilizada.Abaixoveremosocdigoescritodeforma correta: for (int i=0; i < 1000; i++) { double *pointer;

15

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

pointer = new double; pointer = i * 3.14159; delete pointer; } Adiferenaentreesteexemploeoanterioraltimainstruodocorpodolao:delete pointer;Esta instruodesalocaamemriaalocadapelonew.Portanto,desumaimportnciaadesalocaodasvariveis quenoseromaisutilizadas,sobpenadecausarumestourodememrianoprograma.Umaobservaoque deve serfeitaaqui : quandoutilizamos o new,caso elenoconsigaalocar amemriacorrespondente, retornar um ponteiro nulo (que possui o valor zero). Portanto, sempre que alocarmos memria dinamicamente,devemosverificarseistorealmentefoifeitocomsucesso,comparandooponteirocoma constanteNULL,paraqueoprogramanoencerreabruptamentedevidoaerrosemtempodeexecuo.

Ponteiros para tipos derivados


PodemosutilizarponteirosparaapontarparaqualquertipodedadosemC++,inclusivearrays,estruturas, uniesetiposenumerados(eobjetos,comoveremosposteriormente).Abaixosegueumexemplodecomo utilizarponteiroscomestruturas(ousocomuniesanlogo): struct TBall { int x, int y, int radius, TColor color } ball_1, *pointer; pointer = &ball_1; (*pointer).x = 10; pointer->y = 20; Portanto, para acessar um membro da estrutura, basta utilizar (*pointer) pois isto desreferencia o ponteiro.Podemosutilizartambmooperadorseta, ->.Comooperadorseta,podemosutilizaroponteiro diretamente,semprecisardesreferencilocom*.

Ponteiros e arrays
EmC++,ponteirosearrayssobastantesemelhantes.Podemosutilizarponteiroscomosefossemarrays(com ooperadorcolchetes,[])eonomedoarraycomoumponteiroparaasuaprimeiraposio.Abaixosegueum exemplodecomoutilizarponteiroscomoarrays: int array[5]; int *pointer; array[0] = 10; array[1] = 20; array[2] = 30; array[3] = 40; array[4] = 50; pointer = &array[0]; cout << pointer[2];

16

CaptuloIEngenhariadeSoftwareEstruturada Oexemploacimaexibir 30comosada.Poderamos fazer aatribuio pointer = &array[0];da seguinteforma:Pointer = array;poisonomedoarrayfuncionacomoumponteiroparaasuaprimeira posio.Observeque,emborapossamosutilizaronomedeumarraycomoponteiro,nopodemosfazer coisasdotipo:array=&array2[0];Portanto,devemosconsiderararrayscomoponteirosconstantes.

Usando new e delete com arrays


Podemoscriararraysemtempodeexecuocomooperadornewemconjuntocom[]: int *pointer; pointer = new int[10]; pointer[0] = 10; ComoC++permiteutilizarmosponteiroscomooperadorcolchetes,[],pointersecomportar comoum array.Paradesalocaramemriaalocadacomnew[],utilizamosdelete[]: delete[] pointer;

Aritmtica de ponteiros
Comosabemos,osponteirossovariveisqueguardamendereosdememria.Porseremvaloresinteiros, podemos utilizar operaes aritmticas com ponteiros. A diferena que, se executarmos a instruo: um_inteiro++;avarivelum_inteiroser acrescidade1.Seexecutarmos:pointer++;avarivelpointerser acrescidadeumnmeroigualaotamanhodotipodepointer,ouseja,sepointerforumponteiroparaint,seu valorseracrescidode4(uminteirotemgeralmente4bytes),deformaque,sepointerestiverapontandopara umaseqnciadeinteiros,pointer++farcomqueeleaponteparaoprximoelemento.Parailustrarmelhora aritmticacomponteiros,segueumexemplo: int *pointer, array[10]; pointer = array; for (int i=0; i<10; i++) { *pointer = i*2; pointer++; } Nesteexemplo,emvezdeacessarmososelementosdoarrayatravsdooperadorcolchetes,[],utilizamosum ponteiroparapercorrlo.Comovimosanteriormente,arrayseponteirossosemelhantes,deformaqueesta aritmticatambmvaleparaarrays:*(array+n)equivalenteaarray[n].

Ponteiros e const
Alm de podermos declarar ponteiros para variveis, C++ nos permite declarar ponteiros para valores constantes: const int *pointer; Istonosignificaqueoponteiros poder apontarparaconstantes.Narealidadeoqueestamosfazendo informandoaocompiladorqueeledevetratarovalorparaoqualoponteiroapontacomoumaconstante,e qualquer tentativa de tratlo de forma diferente causar erro de compilao. A importncia de utilizar ponteirosdestaforma,nosprevenirmosdeerrosqueocorreriamseovalorfosseinadvertidamentealterado.

17

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Outromotivo ques ponteirosparaconstantespodemapontarparaconstantes,osponteirosnormaisno (istoumtantoquantobvio). Apalavrachave const tambmpodeserutilizadaparadeclararponteirosconstantes(noteadiferenade ponteirosparaconstantes).Comoeradeseesperarponteirosconstantesspoderoapontarparaumendereo dememriaconstante,ouseja,nopodemalteraroendereocontidonele.Exemplo: int um_inteiro; int *const pointer = &um_inteiro; Portanto,comovoc j devedesconfiar,tambmpodemoscriarponteirosconstantesparaconstantes,oque significaquenopoderemosalteraroendereocontidoneleequeovalorcontidonesteendereosertratado comoconstante: int um_inteiro; const int *const pointer = &um_inteiro;

Funes
Comovimosnoinciodocaptulo,asfunessoabasedaengenhariadesoftwareestruturada.Entovamos aelas!

Definindo funes
Paradefinirumafuno,utilizamosaseguinteestrutura: tipo nome(argumentos...) { instrues; return expresso_de_retorno; } Onde: tipo:otipoderetornodafuno. nome:onomedafuno. argumentos: lista de zero ou mais parmetros que devem ser passados funo quando a mesma chamada. instrues:conjuntodeinstruesqueseroexecutadasquandoafunoforchamada. expresso_de_retorno:expressoretornadaparaopontoondeafunofoichamada.Deveserdo mesmotipodetipo. Abaixosegueumexemplodeumadefiniodefuno: int add(int numero_1, int numero_2) { int numero_3; numero_3 = numero_1 + numero_2; return numero_3; } Claroqueasfunesquenscriamossogeralmenteumpoucomaiscomplexas,masesteexemploilustra bemoselementosdadefiniodeumafuno. Em C++, alm de definirmos umafuno (com todos os seus elementos), devemos tambm declarar as funesquedefinimos.Estadeclarao chamadadeprottipodeumafuno.Oprottipodeumafuno nadamaisdoqueaprimeiralinhadadefiniodafunoseguidadeumpontoevrgula.Ex:

18

CaptuloIEngenhariadeSoftwareEstruturada

int add(int numero_1, int numero_2); Ocdigoacimademonstraoprottipodafunoadd,definidanoexemploanterior. Paraestruturarmelhorocdigo,criamosumarquivocomextensocppcomasdefiniesdasfuneseum arquivocomextenso.hcomosprottiposdasfunes.

Argumentos e tipos de retorno de funes


Podemospassarqualquertipodedadoscomoargumento(ouparmetro)paraumafuno.Abaixoveremos algumaspeculiaridadesdostiposdedadosmaiscomplexos,ecomoretornarestestipos. Funes e arrays Parapassarumarrayparaumafuno,bastaadicionar[]aonomedoargumento,ex: int add(int array[], int num_elementos) { int resultado=0; for (int i=0; i<num_elementos; i++) { resultado += array[i]; } return resultado; } bastanteimportanteressaltaroqueestacontecendoaqui.AolembrarmosqueC++trataonomedearrays comoponteirosconstantes,podemosperceberqueoqueestamospassandocomoargumentonoumacpia dequalquerelementodoarray,massimumponteiroparaoarrayoriginal.Comopodemosutilizarponteiros comoarrays(comooperador[]),aprimeiravista,ocdigoacimapodenodemonstrarorealmenteest acontecendo.Portanto,sealterssemosqualquerelementodoarray,estaramosalterandonoarrayoriginal. Para prevenirmos alteraes inadvertidas, devemos declarar oparmetro doarray comoconstante, como veremosabaixo: int add(const int array[], int num_elementos) { int resultado=0; for (int i=0; i<num_elementos; i++) { resultado += array[i]; } return resultado; } Destaforma,garantimosqueapassagemdeparmetrosporrefernciaqueestimplcitanoimpliqueemum errogravenonossoprograma. Retornando um array de uma funo OC++nopermiteatribuirumarrayinteiroaoutro,nemretornarumarrayinteirodeumafuno.Portanto, pararetornarumarraydeumafuno(eeventualmenteatribuiristoaoutro),devemosusarponteiros.Como existeumasemelhanaentreponteirosearrays,esteprocessobastantesimples.Vejamosumexemplo: int *init_array(int num_elementos)

19

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

{ int *retorno = new int[num_elementos]; for (int i=0; i<num_elementos; i++) { retorno[i] = 0; } return retorno;

Devemosobservarosseguintesaspectosnotrechodecdigoacima: Otipoderetornodafuno narealidadeumponteiro,comoj foiexplicadoantes.Portanto,o resultadodestafunospodeseratribudoaponteiros,enoaarrays. A varivel de retorno no foi declarada como um array normal como: int array[num_elementos] pois, se fosse declarada desta forma, seria alocada na rea de armazenamentoautomtico,sendodesalocadaaofinaldoseuescopo,ouseja,nofimdafuno. Ento,quandotentssemosutilizaroarrayderetornodafunoestaramostrabalhandocomuma readememriadesalocada,quepoderiaconterqualquercoisa,oupior,tersidoalocadaparaoutra varivel. Notequealocamosmemriadentrodestafunoenodesalocamos.Portanto,tarefadocdigoque chamouafunodesalocarestamemriacomooperadordelete[],quandoeladeixardeserutilizada. Funes e estruturas EmC++,asestruturassopassadasparaasfunescomovalor,deformaquepassarumaestruturaparauma funoomesmoquepassarumavarivelsimples.Exemplo: struct structure { int um_inteiro; char um_char; }; void function(structure uma_estrutura) { cout << Exibindo o nmero: <<uma_estrutura.um_inteiro<<endl; cout << Exibindo o char: << uma_estrutura.um_char << endl; } Napassagemdeparmetrosporvalor,oqueacontece queaestruturapassada copiadaparaumavarivel local,noarmazenamentoautomtico.Portanto,parapassarestruturasgrandespodemosoptarporpassarum ponteiroparaaestrutura,evitandoassimooverhead2dacpia. Omesmoseaplicaaoretornarestruturasdeumafuno,aestruturatambmpassadaporvalor.Exemplo: structure get_structure() { structure estrutura; estrutura.um_inteiro = 0; estrutura.um_char = A; return estrutura; }
2

Tempogastocomexecuodecdigoquenofoicriadopeloprogramador,equeportanto,nofazpartedo programadiretamente. 20

CaptuloIEngenhariadeSoftwareEstruturada

Comoaestruturapassadaporvalor,noprecisamosnospreocuparcomseuescopo.Narealidade,avarivel estrutura perdeoescopoaofimdafuno,mascomooque retornado umacpiadamesma,no precisamosnospreocuparcomisto.

Ponteiros para funes


Comovimosanteriormente,podemosutilizarponteirosparaqualquertipodedados.Nestaseoveremosque tambmpodemosutilizarponteirosparafunes.Comoasfunessodadoscompiladosarmazenadosna memria,nadanosimpedequetenhamosumponteiroparaestesdados.Umponteiroparafunoapontapara posiodememriaparaaqualoprograma transferidoquandoafuno chamada.Utilizamosponteiros parafunesparapassarestasfunescomoargumentoparaoutrasfunes.Seoprottipodeumafuno: int funo(int i); Umponteiroparaestafunopoderiaserdeclaradodaseguinteforma: int (*ponteiro_para_funo)(int i); Damesmaformaqueonomedeumarrayumponteiroconstanteparaoarray,onomedeumafunoum ponteiroconstanteparaafuno,deformaquepodemosinicializaronossoponteirodaseguinteforma: ponteiro_para_funo = funao; Parapassarmosumafunocomoparmetroparaoutra,passamosafunocomoponteiro: void funo2((*ponteiro_para_funo)(int i)) { int parmetro = 13723; (*ponteiro_para_funao)(parametro); } Como podemos observar, funo2 recebe uma funo como parmetro e chama esta funo com o argumento13723.

Funes in-line
Quandofazemosumachamaaumafuno,ofluxodoprogramadesviadoparaoendereodafuno,seus argumentossocolocadosnapilha,entreoutrascoisas.Istogeraumoverheadnaexecuodeumprograma. Parasituaescrticas,oufunesbastantepequenas(comumaouduasinstrues),C++nospermitecriar funesinline.Nolugardaschamadasaestasfunes,ocompiladorcolocatodoocdigodafuno,de formaquenenhumdesvionecessrio.Adefiniodeumafunoinlinefeitacomapalavrachaveinline: inline int dobro(int num) { return 2*num; } Destaforma,todavezquefizermosumachamada funo dobro,ocdigo:2*numser colocadoemseu lugar.

Um pouco mais sobre argumentos

21

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

C+ tambm nos permite utilizar os argumentos de funo de forma bastante eficiente. Podemos definir argumentospadroouumnmerovariveldeargumentosparaumafuno,comoveremosaseguir. Argumentos padro Definindoargumentospadroparaumafuno,estamosespecificandoumvalorqueser utilizadocasono seja fornecido nenhum valor para o argumento. Para definir um argumento padro para uma funo, utilizamosoigual,=,seguidopelovalor_padro,nadefiniodoprottipodafuno: int sum(int num1, int num2 = 1); int sum(int num1, int num2) { return num1+num2; } result = sum(10); Nocdigoacima,comonum2foideclaradocomvalorpadroiguala1,semprequefizermosumachamadaa sumsemosegundoargumento,ovalor1ser utilizadonoseulugar.Portanto,quandodefinimosumvalor padroparaumargumento,devemosomitiresteargumentoparautilizarseuvalorpadro.Istoquerdizerque osargumentospadrodevemserosltimosargumentosdafuno,pois,casoistonoocorra,ocompilador serincapazdeidentificarqualdosargumentosestfaltando. Argumentos variveis Almdedefinirargumentospadro,C++disponibilizaumconjuntodemacrosparaquepossamosdefinir umafunocomumnmerodeargumentosvarivel.Estasmacrosso: va_list:obtmalistadeargumentospassadosparaafuno va_start(va_list list, int num_elementos):inicializaalista va_arg(va_list list, tipo):retornaumargumentodalista va_end(va_list list):finalizaousodalistadeargumentos Parautilizarmosasmacros,devemosincluiroarquivodecabealho cstdarg.Abaixosegueumexemplo quemostracomocriarumafunocomumnmerodeargumentosvarivel: int sum(int...); int main () { cout a soma de 1, 2 e 3 : << sum(3, 1, 2, 3) << endl; return 0; } int sum(int num_elementos ...) { int resultado = 0, numero; va_list lista; va_start(lista, num_elementos); for(int i = 0; i < num_elementos; i++) { numero = va_arg(lista, int);

22

CaptuloIEngenhariadeSoftwareEstruturada resultado += numero; } va_end(lista); } return resultado;

Nesteexemplo,afunosumrecebeumargumentoobrigatrio,que aquantidadedeargumentosvariveis que estamos passando, seguido de vrios argumentos. Ento, utiliza as macros para percorrer a lista de argumentosesomlos.

Sobrecarga de funes
svezes,desejamoscriarumafunoquepossaserchamadacomdiferentestiposdeargumento.Istonos permitepersonalizarocdigoetornlomuitomaisfcildetrabalhar.C++permitequesobrecarreguemos funesparaqueestasaceitemargumentosdetiposenmerosdiferentes.Paraisto,bastaapenasdefiniras funestantasvezesquantasforemnecessrias.Notequeaassinatura,listadeargumentosdafuno,deveser diferente, ouseja:otipoouaquantidade(noapenas onome)dosargumentos deveserdiferentes,nas diferentesversesdeumafunosobrecarregada.Abaixosegueumexemplodesobrecargadefuno: int sum(int &num1, int num2); char *sum(char *str1, const char *str2); int main() { int num1= 10, num2 = 15, num3 = 20; char const *str1 = "World!"; char str2[20] = "great "; char str3[20] = "Hello "; cout cout cout cout cout cout cout cout cout cout << << << << << << << << << << "--- Funcao sum com inteiros ---" << endl; "soma total: " << sum(num3, sum(num2, num1)) << endl; "num1: " << num1 << endl; "num2: " << num2 << endl; "num3: " << num3 << endl << endl; "--- Funcao sum com strings ---" << endl; "Strings: " << sum(str3, sum(str2, str1)) << endl; "str1: " << str1 << endl; "str2: " << str2 << endl; "str3: " << str3 << endl;

cin.get(); return 0; } int sum(int &num1, int num2) { return (num1 = num1 + num2); } char *sum(char *str1, const char *str2) { return strcat(str1, str2); } 23

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Nocdigoacima,afunosumpodeserutilizadadamesmaformacominteirosestrings.Foiutilizado const char*str2,comosegundoargumento,paragarantirqueesteargumentonoseriamodificadono corpodafuno.

24

CaptuloIEngenhariadeSoftwareEstruturada

Seo prtica: definindo nosso projeto


Parafixarnossosconhecimentos,teremoscomoprojetoprticoumjogoemC++.Estejogoirevoluiracada captulo,sempreutilizandoosnovosconceitosestudados. Portanto,desenvolveremosumjogodotipoArcanoid,noqualojogadorcontrolaumabarra,localizadaem baixodatela,etemcomoobjetivodestruirumconjuntodeblocosrebatendoumabolinha.Estejogoser desenvolvido em modo texto, pois estamos focando o ANSI/ISO C++, que compatvel com qualquer sistemaoperacional,eautilizaodeumambientegrficodependedosistemaoperacionalutilizado.Abaixo segueummodelodateladojogo:

Comoprticadestecaptulo,iremosprojetaronossojogoutilizandofunes.Iremoscriarfunespara: Apagaratela Desenhareapagarumblocoemumaposiodatela Desenhareapagarabarraemumaposiodatela Desenhareapagarabolaemumaposiodatela Moverabolaetestaracolisocomosoutrosobjetos Moverabarradeacordocomentradadoteclado

Abaixoseguemasseqnciasdecaracteresdeescapequemodificamoestadodatela,seenviadasparacout (ESCsignificaocaracteredeescape,cujocdigoascii27): Funo Normal Bold Blink (piscando) Reverso (cores do texto e fundo trocadas) Mover para a posio 0,0 Mover para a posio x,y Apagaratela Mudaracorparaatr,fg,bg(atr=0(normal)ou atr=1(highlight),fg=texto,bg=fundo) Seqnciadecaracteres ESC[0m ESC[1m ESC[5m ESC[7m ESC[f ESC[f ESC[yB ESC[xC ESC[fESC[2J ESC[atr;fg;bgm

Noteque atr e fg definemacordotextoenquanto bg defineacordefundo.Osvaloresque atr, fg e bg podemassumirso: 25

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Cor Preto Vermelho Verde Marrom Azul Magenta Ciano Cinzaclaro Cinzaescuro Vermelhoclaro Verdeclaro Amarelo Azulclaro Magentaclaro Cianoclaro Branco

Valordeatr 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

Valordefg 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37

Valordebg 40 41 42 43 44 45 46 47

Agoraj temoscomomanipularasadadecaracteres natela.Voc deveutilizaroarquivo screen.h que contmasdefiniesmencionadasacimaecriaraprimeiraversodonossojogo,queimplementeasfunes necessriasvistasanteriormente.

26

Captulo II

Engenharia de Software Baseada em Objetos

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Engenharia de software baseada em objetos


Modularidade, coeso e acoplamento
Comocrescimentodacomplexidadedosprogramas,tornousedegrandevaliaadecomposiodosmesmos em unidades menores. A decomposio de um programa em mdulos permite diminuir o tempo de programaoaoseprogramarosmdulosemparalelo,divideoproblemaaserresolvidoempartesmenorese mais fceis de serem implementadas e permite compilar e testar estas partes separadamente. Mas a modularizao no traz s vantagens. Uma modularizao mal feita pode acarretar em problemas com reusabilidade, extensibilidade, compatibilidade, etc. Os fatores que influenciam na modularizao so: a coeso, interdependncia das funes e estruturas internas de um mdulo; e o acoplamento, nvel de dependnciaentreosmdulos.Portanto,paramodularizarumprogramacorretamente,devemos: Maximizaracoeso:asfuneseestruturasdedadosqueimplementamumafuncionalidade(ou conjuntodefuncionalidadesrelacionadas)doprogramadevemestarnomesmomdulo. Minimizaroacoplamento:osmdulosdevemfuncionarosmaisindependentespossveisdosoutros mdulos,paraqueaomodificarmosummdulonosejanecessriomodificarosdemais.

Amodularizaotambmdeveseguirdoisprincpios: informationhidding3 ereusabilidade,queveremosa seguir.

Information Hidding
Para garantir um fraco acoplamento entre os mdulos, devemos fazer com que um mdulo conhea somenteonecessriosobreofuncionamentointernodosmdulosqueeleutiliza.Portanto,devemosdefinir uma interfaceparacomunicao entreosmdulos,deformaquenosejavisvelasuaestruturainterna, apenasasuainterface. Ento,depoisdedefinidososconceitosbsicosdaengenhariadesoftwarebaseadaemobjetos,podemos formularumadefiniodemdulomaisconcretaequeserusadadeagoraemdiante: Um mdulo possui uma srie de operaes (funes) e um estado (variveis), que guarda o efeito das operaes. Possui tambm uma interface: conjunto de dados e operaes que esto disponveis aos outros mdulos; e uma implementao: definio das estruturas de dados e do corpo das funes. Esta definio de mdulo o que chamamos de estrutura de dados abstrata.

Suporte modularidade em C++


C++permiteadivisodenossosprogramasemdiversosarquivos,deformaapodermosterarquivospara cada mdulodenossoprograma. Asinterfaces dosmdulossodefinidasem arquivoscomextenso .h (arquivosdecabealhodeC++)enquantoaimplementaoestnosarquivoscomextenso.cpp.Quandoum mdulonecessitarutilizaroutro,deveincluiroarquivodecabealhocorrespondenteeainterfacedomdulo aserutilizadoficardisponvel. Definindo interfaces

Informationhiddingumconceitodeengenhariadesoftwarequeconsisteemencapsularosdadosdeum mdulodeformaqueestesssejamacessveisatravsdainterfacedomdulo. 28

CaptuloIIEngenhariadeSoftwareBaseadaemObjetos Asinterfacesdosmdulossocriadasemarquivos.h.C++permiteacriaodeespaosdenomesseparados paracadamdulo,paraquenosecorraoriscodeexistirconflitoentrenomesdedadosoufunesiguaisem mdulosdiferentes.Istofeitoutilizandoseapalavrachavenamespace. Comovimosanteriormente,podemosutilizaraspalavraschave externestaticparadefiniraligao(externa ouinterna)dosdados.Veremosestesconceitosnaprticanaprximaseo. Organizao dos arquivos Abaixosegueummodelobsicodosarquivosdeummdulochamadomodulo1,comexplicaessobresuas partes: //----------------------------------------------------------------/* Arquivo modulo1.h */ #ifndef MODULO1_H #define MODULO1_H namespace modulo1 { // verifica se o arquivo j foi chamado // anteriormente para que no haja redefinio // do mdulo // indica que as definies abaixo pertencem ao // espao de nomes do modulo1

// definio das funes e estruturas de dados da interface // do mdulo extern void printResults(); extern int funcao1(int num1, int num2); extern char *str1; } #endif /* fim de modulo1.h */ //----------------------------------------------------------------/* Arquivo modulo1.cpp */ #include modulo1.h namespace modulo1 { // inclui a interface do modulo 1

// indica que as definies abaixo pertencem // ao modulo1

// definicoes privadas static int funcao1(int num1, int num2); static char *str1 = "Modulo 1 - variavel privada"; // variavel publica char *str2 = "Modulo 1 - variavel publica"; // funcoes publicas int funcao2(int num1, int num2) { return num1*num2; } void printResults() { cout <<"Usando funcao1 do modulo 1: "<<funcao1(1, 2)<<endl;

29

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

cout <<"Imprimindo str1 do modulo 1: "<< str1 << endl; } // funcao privada static int funcao1(int num1, int num2) { return num1+num2; } } /* fim do arquivo modulo1.cpp */ //----------------------------------------------------------------Tipos abstratos de dados Neste captulo, aprendemos conceitos importantes da Engenharia de Software baseada em objetos. A modularizaodeumprogramatrazdiversasvantagens,poispermiteadivisodetarefas,tornamaisfcila implementaoepermitetestesmaisespecficos.Masoquefazersenecessitarmosdemaisdeumainstncia deummodulo?Umasoluoseriacopiarecolarosmdulosemarquivosdiferentes,tantasvezesquantas foremnecessrias,masistovaideencontroaosprincpiosdaextensibilidadeereusabilidade.Nocaptulo anterior,vimoscomocriartiposdedadoscompostos,estruturaseunies.Comoumaestruturaumnovotipo dedado,podemostervriasinstnciasdeumaestrutura.Acombinaodadivisodoprogramaemmdulos com arepresentao dos dados domduloatravs deestruturas oquechamamos de Tipos deDados Abstratos(ADTAbstractDataType). Almdasregrasaseremseguidasparaconstruodemduloseestruturas,aconstruodeumADTdeve levaremcontaasseguintesfuncionalidades: Construo:deveserpossvelalocareinicializarnovasinstnciasdoADT. Atribuio:devemospodercopiarosdadosdeumainstnciaparaoutra. Comparao:deveserpossvelcompararduasinstnciasdeumADT(ateno sdiferenasentre identidadeeigualdade) Manipulaodosdados:devemospodermanipularosdadosdeumADTsemsepreocuparcoma formadearmazenamentointerno,deformaaencapsularoADT. Destruio:devemosterapossibilidadedeliberaramemriaalocadaporumADT,quandono formosmaisutilizlo.

AodefinirmosumADTtendoemmenteestasresponsabilidadesestaremosimplicitamenteaplicandotodosos conceitosdeengenhariadesoftwarequeaprendemosatagora.

Suporte reusabilidade: Modelos de funo


Comovimos,C++ umalinguagemfortementetipada,oquenosimpedede,aodefinirmosumafunoque manipulainteiros,utilizalacomnmerosdepontoflutuante,porexemplo.Sedesejarmosumafunoque tenhaomesmocomportamento(asmesmasinstrues)paraambososcasos,podemossobrecarregaresta funo,masistofeririaoconceitodereusabilidadedecdigo,poisteramoscdigosidnticosreplicados. MasoC++ofereceumaalternativaparaisto:podemoscriarmodelosdefuno,queindependamdotipode dados, e utilizar este modelo para ambos os tipos. Para criar modelos de funo (function templates), utilizaremosaspalavrastemplateetypename: template <typename T> void add(T &num); int main() { int num1 = 10;

30

CaptuloIIEngenhariadeSoftwareBaseadaemObjetos float num2 = 12.34; double num3 = 56.7890; add(num1); add(num2); add(num3); cout << num1: << num1 << endl; cout << num2: << num2 << endl; cout << num3: << num3 << endl; cin.get(); } return 0;

template <typename T> void add(T &num) { num++; } Comopodemosperceber,ocompiladorseencarregoudegerarafunoparacadatipodedado.Masoque ocorreriaseutilizssemosumtipoparaoqualafunono adequada?Afunoaddfuncionamuitobem paratiposnumricos,masnoseriaadequadaparastringsporexemplo.Podemos,entodefinirumafuno addparaotipostringqueexibaumamensagemdeerro,informandoqueaddnoadequadaparastrings.Isto feitocriandoespecializaesdafunotemplate.Paracriarumaespecializaoparaumdeterminadotipo, utilizamostemplate<>,edeclaramosafunocomotipodesejado: template <> void add (char *str) { cout << No possvel adicionar um string << str << endl; }

31

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Seo prtica: estruturando o nosso projeto em mdulos


Continuandocomoprojetodonossojogo,iremosdividironossoprojetoemmdulosbuscandotornloso maisindependentepossvelunsdosoutros.Osmdulospodemserdivididosdaseguinteforma: screen.cpp game.cpp sprites.cpp noid.cpp responsvelpelasrotinasdedesenhoemanipulaodeimagensnatela. responsvelpelocontroleprincipaldojogo,pontuaoeentradadoteclado. responsvelpelocontroleemovimentaodoselementosdojogo(blocos,bolaebarra). Possuiafunomainepossveisfunesauxiliares.

Devemos definir as interfaces de cada mdulo antes de comear a implementlos. Faa diagramas representandoasrelaesentreosmdulosparaajudlo.Osmdulosdevemserimplementadosseguindoos princpiosdeumADT.

32

Captulo III

Engenharia de Software Baseada em Classes

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Engenharia de Software Baseada em Classes


Nocaptuloanterior,vimoscomocriartiposabstratosdedados.Oprocessodedividirumproblemaempartes facilmentemanipulveischamadodeabstrao.OC++forneceumsuporteconstruodetiposabstratos, comautilizaodeestruturas,efunesqueasmanipulem.Emborasejafuncional,estaabordagemnoest completamentedeacordocomosconceitosdeencapsulamentoemodularidade.Pararesolverestesproblemas foiintroduzidoemC++oconceitodeclasse.Umaclasse ummoldeapartirdoqualpodesecriartipos abstratos,ou,comochamamos,objetos.Nestecaptuloveremoscomodefinirclassesevriaspeculiaridades destasentidadesemC++.

Classes em C++
Vamosiniciaronossoaprendizadopartindodeumaestrutura.Damesmaformaqueadicionamosvariveis, podemosadicionarfunesaumaestrutura: struct TBall { int x, y; TColor color; int radius; void move(int x_step, int y_step) { x += x_step; y += y_step; }

};

Portanto,aestruturaTBallagorapossuiumafunomembro.Istosignificaqueafunopertenceestrutura es podeserchamadaapartirdela.Tambmpodemosobservarqueosmembrosdaestruturasovisveis dentrodafunomembro.Paratransformarestaestruturaemumaclasse,asnicascoisasquedevemosfazer so:substituirstructporclasseadicionarapalavrachavepublic:paraindicarquepodemosacessar osmembrosdaclasse: class TBall { public: int x, y; TColor color; int radius; void move(int x_step, int y_step) { x += x_step; y += y_step; }

};

Comestesexemplospodemosperceberumadasdiferenasentreclasseseestruturas:nasestruturas,todosos membrossopblicos,enquantonasclassespodemosdeterminaravisibilidadedosmembrosatravsdos seguintesmodificadores:

34

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses public:tornaosmembrosdaclassevisveisforadaclasse protected:osmembrosdaclassessovisveisdentrodaprpriaclasseenasclassesderivadas (veremoscomocriarclassesderivadas,ousubclasses,noprximocaptulo). private: osmembrosdaclassessovisveisdentrodaprpriaclasse.

Portanto,umavezvistocomodefinirumaclasse,eisumexemplodaclasse TBallcomtodososrequisitos deumADT: class TBall { private: // os atributos da classe so todos privados // lembre-se do conceito de information hidding int x, y; TColor color; int radius; public: // Todos os mtodos de manipulao de atributos, os // construtores e o destrutor devem ser pblicos. // // // // // // Construtores da classe TBall, servem para alocar memria e inicializar os objetos da classe. Os construtores so mtodos que devem possuir o mesmo nome da classe e so chamados sempre que um novo objeto da classe criado. Abaixo temos dois construtores para a classe:

// Construtor 1: no possui parmetros, inicializando os // atributos com valores padro. TBall () { x = 0; y = 0; color = clBlack; radius = 1; } // Construtor 2: permite que os atributos sejam inicializados // com os valores desejados. TBall (int x1, int y1, TColor c, int r) { x = x1; y = y1; color = c; radius = r; } // Destrutor da classe TBall. Deve possuir o mesmo nome da // classe precedido de um ~. chamado toda vez que um // objeto destrudo (com o operador delete). // No seu corpo geralmente existem instrues para desalocar as // variveis criadas dinamicamente. Como no existem atributos // desta forma, o corpo do destrutor est vazio e sua // declarao poderia ser omitida. Foi exibida aqui a ttulo de // exemplo de destrutor. ~TBall{} // Alm dos construtores e do destrutor, devemos fornecer 35

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

// mtodos pblicos para manipular os atributos da classe. void move(int x_step, int y_step) { x += x_step; y += y_step; } int getX() { return x; } int getY() { return y; } TColor getColor() { return color; } int getRadius() { return radius; } void setColor(TColor c) { color = c; } void setRadius(int r) { radius = r; } }; Portanto,aestanossaprimeiraclasse,seguindotodososrequisitosdaengenhariadesoftware.importante salientarqueumaclassepodecontertantosconstrutoresquantosforemnecessrios,masdevepossuirum nicodestrutor.Comoodestrutor chamadopelaestruturainternadoprograma,quandoumobjetosaido escopoouquandoutilizamosooperadordelete,umdestrutornopossuiparmetros.

Classes: organizao em arquivos


Apesar de poder criar classes da forma como criamos anteriormente, C++ nos d a possibilidade de separarmosadeclaraodaclasse(arquivos.h)desuaimplementao(arquivos.cpp).Destaforma,podemos utilizaraclasseemdiversosoutrosarquivos,bastandoparaistoincluiroarquivodecabealhoquecontma definiodaclasse.Narealidade,esta aformacorretadeimplementao,poisaodefinirmosumaclasse comocorpodosmtodosnadeclarao,ocompiladortrataistocomosefosseumadeclaraoimplcitade mtodosinline,oqueno desejadoparatodososmtodos.Abaixosegueumexemploresumidodecomo dividirumaclasseemarquivosdecabealhoeimplementao: /* Arquivo TBall.h */ 36

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses

#ifndef TBALL_H #define TBALL_H class TBall { private: int x, y; TColor color; int radius; public: void move(int x_step, int y_step); // declarao dos mtodos . . .

};

#endif /* fim de TBall.h */ /*Arquivo TBall.cpp*/ void TBall::move(int x_step, int y_step) // corpo do mtodo { x += x_step; y += y_step; } . . . /* fim de TBall.cpp*/ Comoumaclassedefineumescopo,aimplementaodosmtodosdeumaclassedevevirprecedidadonome daclasseseguidopelooperadordeescopo::.

Modificadores de mtodos
Almdaformanormaldedeclararmtodos,C++ofereceumconjuntodemodificadoresdemtodos(alguns jvistoscomfunes)quealteramaformacomoestessoutilizados. Mtodos in-line Comovimos anteriormente, os mtodos cuja implementao est dentro dadefinio da classe so,por padro,inline.Umaoutraformadecriarmtodosinlineutilizandoapalavraclave inline,comoveremosa seguir: inline void TBall::setColor(TColor c) { color = c; } Adeclaraodomtodonadefiniodaclassecontinuasendofeitadamesmaforma. Mtodos constantes

37

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Sedeclararmos umobjetodeumaclassecomoconstante,comousode const,s poderemoschamaros mtodosdoobjetoqueforemconstantestambm,ouseja,ummtodoserchamadoconstantesignificaqueo mtodonoalterar osatributosdoobjeto.Osmtodosconstantestambmsodeclaradoscomapalavra chaveconstcolocadaapsalistadeargumentosdomtodo: TColor TBall::getColor() const { return color; }

Como criar membros estticos


Como vimos anteriormente, podemos declarar variveis externas como estticas para tornar sua ligao interna e declarar variveis automticas comoestticas para mudar asua classede armazenamento para esttica.Emumaclassepodemosutilizaromodificadorstaticdeduasformas: Usandostaticcomumatributo,tornamosesteatributocompartilhadocomtodososobjetosdaclasse, ouseja,todososobjetosdaclassecompartilhamamesmaposiodememriaparaesteatributo. Usandostaticcomummtodo,estesetornamtododaclasse,enodoobjeto,deformaqueno precisamosinstanciarumobjetodaclasseparachamaromtodo.Comoosmtodosestticosno fazempartedenenhumobjetodememria,eless podemacessarosatributosestticosdaclasse. Parachamarummtodoesttico,procedemosdaseguinteforma: class TBall { public: static string getInfo(); . . . }; static string TBall::getInfo() { return This is a ball; } int main () { cout << TBall::getInfo() << endl; return 0; }

O ponteiro this
TodaclasseemC++possuiumponteiroespecialchamadothis,queapontaparaainstanciaatualdoobjeto. Porexemplo,secriarmosummtodoquenecessiteretornaroprprioobjeto,podemosutilizarthisparaisto. Ex: class TBall { TBall & compare(const TBall &ball); . .

38

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses . }; TBall & TBall::compare(const TBall &ball) { if (radius >= ball.radius) return *this; else return ball; } int main () { TBall ball1(10, 20, clWhite, 30); TBall ball2(30, 100, clBlack, 10); cout << A bola maior a << ball1.compare(ball2).getColor.getName() << endl; } return 0;

Asadadoprogramaser: A bola maior a branca Podemosperceber,nesteexemplo,quepassamoseretornamosoobjeto TBallporreferncia.Porqueisto feito?VocdevelembrarqueoC++,aopassarumestruturaparaumafuno,passaaporvalor,fazendouma cpiadaestruturana readearmazenamentoautomtico.Comobjetosaconteceomesmo.Paraevitareste overhead da cpia, os parmetros so passados por referncia, e, quando no sero alterados dentro do mtodo,sopassadoscomorefernciaconstante.

Sobrecarga de mtodos e construtores


Domesmomodoquesobrecarregamosfunes,C++nospermitesobrecarregarmtodoseconstrutores.Para isto, redefinimos o mtodo ou construtor com uma assinatura (lista de argumentos) diferente. Ento o compiladorseencarregadeverificarqualdasformassobrecarregadasdomtodoouconstrutorserutilizada, combasenasualistadeargumentos.

Construtores de cpia
Osobjetos,comoasestruturas,sopassadosdeeparafunes/mtodosporvalor.Istoquedizerque,ao retornarmosumobjeto,porexemplo,umacpiadoobjetopassadaemseulugar.Istotambmocorrequando fazemosumaatribuio,comooperadorigual,=(veremoscomocorrigiresteproblemacomasobrecargado operadorigual,=,maisafrente,nestecaptulo).Entooqueaconteceseoobjetotivermembrosqueso ponteiros?Exatamente!Apesardoponteirosercopiado,elecontinuaapontandoparaamesmaposiode memriaqueoponteirodoobjetoantigo.Portanto,oobjetoantigoeonovoteroumamesma reade memriacompartilhada. Para resolveresteproblema, C++oferece os construtores decpia. Narealidade, todaclassepossuium construtordecpiapadro,quesimplesmentecopiaosvalores dosmembrosdeumobjetoparaooutro. Quandodefinimosumaclassequetemmembrosquesoponteiros,devemoscriaronossoprprioconstrutor decpia.Paraisto,bastacriarmosumconstrutorquerecebaumarefernciaconstanteparaumobjetoda mesma classe. Neste construtor, podemos reinicializar quaisquer ponteiros ou outros dados, conforme a necessidade,paracriarmosanovacpiadoobjeto.Vejamosumexemplo:

39

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

class TPlayer { private: char *name; int score; public: TPlayer(char *str, int scr); Tplayer(const TPlayer & player); . . . }; TPlayer::TPlayer(char *str, int scr) { name = new char[strlen(str)+1]; strcpy(name, str); score = scr; } TPlayer::TPlayer(const TPlayer & player) { name = new char[strlen(player.name)+1]; strcpy(name, player.name); score = player.score; } Usarconstrutoresdecpiadevesetornarumhbitodaquiparafrente,principalmentesetivermosobjetosque armazenemponteiros.

Funes, mtodos e classes friend


Criando funes friend Funes friend (amiga) umaclasseespecialdefunesquetemacessoatodososmembros(pblicos, protegidoseprivados)deumaclasse.Isto bastante tilquandotemosvriasclassesenoqueremoscriar ummesmomtodoutilitrioparacadaclasse.Emvezdisso,declaramosumafunocomofrienddetodasas classes.Exemplo: class TPlayer { private: char *name; int score; public: friend void display(const Tplayer & player); . . . }; void display(const TPlayer & player) {

40

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses cout << Nome: << player.name << endl; cout << Score: << player.score << endl;

Devemosutilizarasfunes friend combastantecuidado,poisseuusoindevidopodecausarumfurono conceitode informtionhidding.Nasprximasseesveremosmaisalgunsmotivosparacriarmosfunes friend. Almdepodercriarfunesfriend,podemoscriarmtodoseclassesfriend.Veremosistonasseesaseguir. Criando mtodos friend Acriaodeummtodofriend anlogadeumafunofriend,anicadiferenaqueestamosutilizando ummtodoenoumafuno(claro!).Vejamosumexemplo: class TPlayer; class TScreen { public: void display(const TPlayer & player); }; class TPlayer { private: char *name; int score; public: friend void TScreen::display(const TPlayer & player); . . . }; void TScreen::display(const TPlayer & player) { cout << Nome: << player.name << endl; cout << Score: << player.score << endl; } NotequetivemosquedeclararaclasseTPlayer (vejaaprimeiralinhadoexemplo)antesdeutilizlano mtododisplaydeTScreen.NopodamossimplesmentetercolocadoaclasseTPlayerantespoisela declaraomtododisplaydeTScreencomofriend,eocompiladorreclamariaqueaindanoviua classeTScreen. Criando classes friend Aodeclararumaclassecomofrienddeoutraclasse,aprimeiratemacessoatodososmembrosdasegunda (comojeradeseesperar).Portanto,todososseusmtodostornamsefrienddasegundaclasse.Exemplo: class TPlayer { private: char *name; int score; 41

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

};

friend class TScreen; . . .

class TScreen { public: void display(const TPlayer & player); }; void TScreen::display(const TPlayer & player) { cout << Nome: << player.name << endl; cout << Score: << player.score << endl; }

Converses entre objetos


Alm de converses entre tipos bsicos, C++ nos permite definir converses entre os nossos objetos, tornandoosomaisparecidospossvelcomostiposbsicosdalinguagem. Converses para objetos Paraconverterumtipodedadosparaumobjeto,devemoscriarumconstrutordeconverso.Esteconstrutor recebe como argumento o tipo de dados e cria um novo objeto, atribuindo este tipo ao membro correspondentedoobjetocriado.Porexemplo,sequisssemosatribuiruminteiroaumobjetodotipo TBall eesteinteirorepresentasseoraiodabola,deveramoscriarumconstrutordaseguinteforma: TBall::TBall(int r) { x = 0; y = 0; radius = r; color = clBlack; } Ento,ocdigoabaixofuncionariacorretamente: TBall ball1; ball1 = 10; Converso a partir de objetos Paraconverterumobjetoparaumtipodedado,utilizamosmtodosespeciais.Porexemplo,paraconverter umTBallparaumint(querepresentariaoraiodabola),declaramosummtododenome: operator int(); Eisumexemplo: class TBall {

42

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses private: int x, y; TColor color; int radius; public: operator int() const; . . .

};

TBall::operator int() const { return radius; } Assim,ocdigoabaixotambmfuncionarcorretamente: TBall ball1(10, 20, clBlack, 30); int raio; raio = ball1;

Sobrecarga de operadores
UmdosrecursosmaisinteressantesepotentesdeC++(eumadasdiferenasentreC++eoutraslinguagens POOcomoJava,porexemplo) apossibilidadedesobrecarregaroperadoresparamanipularosobjetosdas classesquecriamos.Aofazersobrecargadeoperadores,devemosseguirasseguintesrestries: nopodemossobrecarregarosoperadores: sizeof,.,::,.*,?:,type_id,const_cast,dynamic_cast, reinterpret_castestatic_cast; os operadores sobrecarregados devem ser usados com pelo menos um operando do tipo sobrecarregado; nopossvelcriaroperadorescompletamentenovosnemmudarumoperadordebinrioparaunrio eviceversa.

Apesardisto,podemossobrecarregartodososdemaisoperadores,inclusivenew,delete,[],+=,<<e>>. Asobrecargadeoperadores semelhante sobrecargademtodos,adiferena queutilizamosapalavra chave operator para indicar que estamos sobrecarregando um operador. Nas sees seguintes, veremos algumaspeculiaridadesdasobrecargadeoperadoresquenecessitamdeumaatenoamais. Sobrecarregando operadores unrios, como ++ e -Parasobrecarregarumoperadorunrio,devemoscriarummtodonaclassecomaseguintesintaxe: tipo operatorop() { } Ondetipo,otipoderetornodooperador,quenestecasoonomedaclassee opooperadoremsi,como+ +ou. Portanto,parasobrecarregarooperador++daclasseTBallqueincrementaoraiodabola,procedemosda seguinteforma: 43

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

class TBall { private: int x, y; TColor color; int radius; public: TBall & operator++(); . . . }; TBall & TBall::operator++() { radius++; return (*this); } Devemosobservarqueestecdigos sobrecarregaooperador++prfixado.Parasobrecarregarooperador psfixado,utilizamos: TBall operator++(int); Ondeoargumentointdiferenciaosoperadores. Sobrecarregando operadores binrios, como + e Parasobrecarregaroperadoresbinrios,devemospassarcomoargumentodooperadorumobjetodotipodo segundooperando(istopermitequeutilizemosesteoperadorcomobjetosdetiposdiferentes,porexemplo).A sintaxe: class TBall { private: int x, y; TColor color; int radius; public: TBall(const TBall &ball); TBall operator+(const TBall &ball); . . . }; TBall TBall::operator+(const TBall &ball) { TBall retBall(0, 0, clBlack, 0); retBall.x = ball1.x + ball2.x; retBall.y = ball1.y + ball2.y;

44

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses retBall.radius = radius + ball.radius; return retBall;

Notequecriamosumnovoobjetodentrodocorpodooperadoreretornamosesteobjeto(narealidadeuma cpiadesteobjeto). Masoqueaconteceriasedesejssemosfazercoisasdotipo:ball = ball + 2ouball = 2 + ball? Comonasegundaexpresso,ooperandono umobjeto,devemosdefinirumafuno friend quereceba ambososoperandos.Vejamosumexemplo: class TBall { private: int x, y; TColor color; int radius; public: TBall(int x1, int y1, TColor c, int r); TBall(int r); friend TBall operator+(const TBall &ball1, const TBall &ball2); . . .

};

TBall::TBall(int r) { x = 0; y = 0; radius = r; color = clBlack; } TBall operator+(const TBall &ball1, const TBall &ball2) { TBall retBall(0, 0, clBlack, 0); retBall.x = ball1.x + ball2.x; retBall.y = ball1.y + ball2.y; retBall.radius = ball1.radius + ball2.radius; return retBall; } DevemosnotarquecriamosumconstrutordeconversodeintparaTBall,demodoestasoluoatendea todasasexpressesvistasanteriormente.Esteumdosprincipaismotivosdousodefunesfriend. Sobrecarregando os operadores >> e << C++permitesobrecarregarosoperadoresdeinseroeextraodefluxo:>>e<<.Parasobrecarregarestes operadores,devemospassarcomoparmetroeretornarofluxocorrespondente(ostreamouistream),para queestesoperadorespossamserencadeados. padrotornarestesoperadores frienddaclasseparaoqual estsendosobrecarregado.Vejamosasintaxedasobrecargadesteoperador: friend ostream & operator<<(ostream &stream, const tipo_classe &c); friend istream & operator>>(istream &stream, const tipo_classe &c); 45

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Sobrecarregando o operador [] Ooperador[],dendicedearray,tambmpodesersobrecarregado.Istonospermiteutilizar ndicesdearray comosobjetospararetornardadosdoarmazenamentointernodoobjeto.Parasobrecarregaresteoperador devemoscriarummtododaseguinteforma: tipo operator[](int index); Ondicedooperadorpassadoparaomtodopeloseuargumentointeiro,nonossocasoindex. Sobrecarregando o operador = Asobrecargadooperadordeatribuio,=,temamesmaimportnciaeusodacriaodeconstrutoresde cpia.Casoesteoperadornosejasobrecarregado,ocompiladorutilizaooperadorpadro,quesimplesmente copia o objeto membro a membro, causando os mesmos problemas com membros ponteiro que vimos anteriormente.Parasobrecarregaresteoperador,criamosummtodonaclassecomaseguintesintaxe: tipo_da_classe & operator=(const tipo_da_classe & objeto); Note que se passarmos o argumento por referncia, devemos retornar o objeto por referncia para que possamosencadearooperadorsucessivamente.

Modelos de classes
OC++permitecriarmodelosdeclasses(classtemplates)damesmaformaquecriamosmodelosdefuno, paradarumamaiorgeneralizaoaonossocdigo.Estesmodelosnospermitemusarummesmoalgoritmo paravriostiposdedados,evitandoreescreverumaclasseparacadatipo.Paracriarmodelosdeclasses, procedemosdeformaanlogacriaodemodelosdefuno: template <lista_de_parmetros> class nome_da_classe { . . . }; AbaixoveremosaclasseTStack,umapilhagenrica. template <typename T> class TStack { private: T element; TStack *next; public: TStack(); TStack(const T &e); TStack(const TStack &stack); ~TStack(); TStack & operator=(const TStack &stack); 46

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses bool isEmpty(); void push(T &e); T pop(); }; template <typename T> TStack<T>::TStack() { next = NULL; } template <typename T> TStack<T>::TStack(const T &e) { element = e; next = NULL; } template <typename T> TStack<T>::TStack(const TStack &stack) { element = stack.element; if (stack.next != NULL) next = new TStack(stack.next); else next = new TStack();

template <typename T> TStack<T>::~TStack() { if (next != NULL) delete next; } template <typename T> T& TStack<T>::operator=( const TStack &stack) { element = stack.element; if (stack.next != NULL) next = new TStack(stack.next); else next = new TStack(); } return *this;

template <typename T> bool TStack<T>::isEmpty() { bool ret = false; if (next == NULL) ret = true; return ret; } template <typename T> void TStack<T>::push(const T &e) {

47

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

if (next != NULL) { next->push(e); } else { element = e; next = new TStack(); } } template <typename T> T TStack<T>::pop() { T e; if (next != NULL) { if (next->next != NULL) e = next->pop(); else { e = next->element; delete next; } } else { e = NULL; } return e; } Devemosnotarosseguintesaspectosnestaimplementao:porutilizarmembrosponteiros,aclassedeveter um construtordecpia,umdestrutor(para liberar amemriaalocada para oponteiro) eooperador de atribuiosobrecarregado(paragarantiracpiadoobjetonaatribuio). Almdapalavrachavetypename,podeservistaadeclaraodeumaclassetemplateutilizandoapalavra chaveclassemseulugar.Estaformadeimplementao,noentanto,estemdesuso,poistypename muito maisgenricodoqueclass. Osmodelosdeclassetambmpermitemmaisdeumtipodedadoscomoparmetrodomodelo.Oseguinte cdigomostracomodefinirummodelodeclassedependentededoistiposdedados: Template <typename T1, typename T2> Class nome_da_classe { . . . }; Note que os outros parmetros podem ser tipos de dados genricos (declarados com typename) como tambmtiposespecficos(charouint,porexemplo).

48

CaptuloIIIEngenhariadeSoftwareBaseadaemClasses

Seo prtica: Criando classes para o jogo


AgoraqueaprendemosadefinirclassesemC++,iremosmodificaronossojogoparaquesejabaseadoem classes.Asclassessugeridasparaonossojogoso: TScreenrepresentandoateladojogo. TBall, TBlock e TBarrepresentandoosspritesdojogo.Estasclassesdevemprovercomunicao comTScreen,comomtodosparaseremdsenhados,etc. TGameclasseparacontrolaradinmicadojogo.Sedesejado,podeconternveis. TPlayerpossuimtodosparainteraocomojogadoreguardaassuasinformaes. Devemos tambm criar um arquivo que contm a funo main e todos os objetos necessrios para o funcionamentodojogo.Asclassesacimasoapenassugestes,e importanteperceberquepodemos(na realidadedevemos)criarclassesauxiliarespararepresentartiposdedadosutilizadospelasclassesprincipais, porexemplo. Notequeprovavelmentesernecessriosobrecarregaroperadores(podemossobrecarregarosoperadores>>e << para conectar aentradaesadadojogocom osnossosobjetos).Noesquea tambm quedevemos implementarasnossasclassescomnomnimo: Construtorpadro Construtordecpia Operadordeigualdadesobrecarregado Destrutor

49

Captulo IV

Engenharia de Software Orientada a Objetos

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Engenharia de Software Orientada a Objetos


Almdepoderdefinirobjetos,C++nospermitedefinirobjetosapartirdeoutrosobjetos. oconceitode herana.Quandoumaclasse(chamadadesubclasseouclassederivada)herdadeoutraclasse(chamada superclasseouclassebase),asubclassepassaapossuirtodososmembrosdasuperclasse,podendoadicionar membrosnovosouredefinirosantigos.Istopossibilitaaoprogramadorumaaltareusabilidadedecdigo, como tambm permite modelar o sistema de uma forma mais fiel ao que acontece na realidade. Neste captulo,veremoscomoutilizarheranaemC++ecomoaproveitartodososbenefciosqueistorepresenta, desenvolvendoumcdigorealmenteorientadoaobjetos.

Herana em C++
VejamosumexemplodecomoutilizarheranaemC++.DefiniremosumaclassechamadaTShape.Apartir destaclasse,criaremosTBlock(bloco)eTBall(bola): class TShape { . . . }; class TBlock : public TShape { . . . }; class TBall : public TShape { . . . }; Comopodemosperceber,paracriarumaclassequeherdadeoutra,bastaapenasincluir: : modificador nome_superclasse apsonomedasubclasse.Omodificadorserveparaespecificarcomoasuperclasseser vistadentroda subclasse.Omodificadorpublicindicaqueosmembrospblicosdasuperclassecontinuamsendopblicosna subclasse. Analogamente, os modificadores protected e private tornam os membros da superclasse protegidosouprivadosnasubclasse.

Overload de construtores, destrutores e mtodos


Vimosnocaptuloanterior,comosobreporosmtodosdeumaclasse.Quandocriamosumaclassederivada, tambm podemossobreporosmtodosdasuperclasse, inclusiveosconstrutores edestrutores. Quandoa superclassenotemumconstrutordefinido,aocriarmosumobjetodasubclasse,oconstrutordasuperclasse chamadoautomaticamente.Masquandotemosconstrutoresdefinidosnasuperclasse,devemosespecificar

52

CaptuloIVEngenhariadeSoftwareOrientadaaObjetos quaisargumentosseropassadosparaessesconstrutores,quandoumobjetodasubclassecriado.Istofeito utilizandoseinicializadores: class TShape { protected: int x; int y; char *name; public: TShape(int x1, int y1, const char *n); ~TShape(); }; class TBlock : public TShape { private: char *pattern; public: TBlock(int x1, int y1, const char *pat); ~TBlock(); }; TShape::TShape(int x1, int y1, const char *n) { x = x1; y = y1; name = new char[strlen(n)+1]; strcpy(name, n); } TShape::~TShape() { delete[] name; } TBlock::TBlock(int x1, int y1, const char *pat) :TShape(x1, y1, block) { pattern = new char[strlen(pat)+1]; strcpy(pattern, pat); } TBlock::~TBlock() { delete[] pattern; } Note que utilizamos :TShape(x1, y1, block) para chamar o construtor da superclasse. Os construtoresdassuperclassessosemprechamadosantesdosconstrutoresdassubclasses.Comosdestrutores ocorreoinverso:osdestrutoresdassubclassessochamadosantesdosdassuperclasses. Asobreposiodemtodosocorredeformasemelhante,adiferena que,parachamarmosmtodosda superclassedentrodasubclasseutilizamos:nome_superclasse::metodo(parametros).

Mtodos virtuais: dynamic binding

53

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Comojvimos,possveltermosponteirosparaobjetosdeumaclasse.OC++tambmpermitequeponteiros paraumasuperclasseapontemparaobjetosdeumaclassederivada,apesardenopoderacessarosmembros especficosdesta.Esteprocesso,deumponteiropoderapontarparadiversosobjetosderivadosdistintos chamadopolimorfismo.Entovoc deveestarpensando:oqueacontecesetivermosummtodosobreposto na subclasse e, com um ponteiro da superclasse apontando para um objeto da subclasse, chamarmos o mtodo?Estconfuso?Vejamosumexemploqueilustreistomelhor: class TShape { protected: int x; int y; char *name; public: TShape(int x1, int y1, const char *n); ~TShape(); void draw(); }; class TBlock : public TShape { private: char *pattern; public: TBlock(int x1, int y1, const char *pat); ~TBlock(); void draw(); }; void TShape::draw() { cout << Drawing a shape << endl; } void TBlock::draw() { cout << Drawing a block << endl; } int main() { TBlock block(10, 20, ####); TShape shape(10, 20, shape); TShape *shapePtr; shapePtr = &shape; shapePtr->draw(); shapePtr = &block; shapePtr->draw(); } return 0;

Asadadoprogramaser:

54

CaptuloIVEngenhariadeSoftwareOrientadaaObjetos

Drawing a shape Drawing a shape Porque?Bem,oponteiroshapePtr dotipoTShapee,apesardepodermosapontarparaumobjetodo tipo TBlock (afinal um TBlock um TShape), ao chamarmos um mtodo atravs do ponteiro, o compiladorfar umaligaoesttica(staticbidingligaoemtempodecompilao)davarivelponteiro comomtododesuaclasse.IstofarcomqueomtododaclasseTShapesejachamadoindependentemente deparaqualobjetooponteiroaponte(afinal,emtempodecompilaono possvelsaberocontedodo ponteiro). Ento,comochamaramosomtodocorreto?OC++ofereceumaalternativaquepermitequealigaodo objetocomomtodosejafeitadinamicamente(dynamicbidingligaoemtempodeexecuo).Istofeito, declarandoomtododasuperclassecomo virtual.Quandodeclaramos ummtododestaforma,estamos avisandoaocompiladorparafazeraligaodoobjetocomomtodoemtempodeexecuo,paraqueo mtododoobjetocorretosejachamado.SenadeclaraodaclasseTShapedoexemploanterior,tivssemos aseguintelinha: virtual void draw(); Asadadoprogramaseria: Drawing a shape Drawing a block IstoquerdizerqueshapePtr>draw()chamaTShape::draw()quandoshapePtrapontaparaum objetodotipo TShape echama TBlock::draw() quando shapePtr apontaparaumobjetodotipo TBlock. Portanto,padroparaosprogramadoresC++ definirsempreosdestrutoresdeumaclassecomovirtuais . Destaforma,estaremosassegurandoqueodestrutorcorretoser chamadoquandoumobjetodeumaclasse derivadafordestrudo.

Classes abstratas
Umaclasse ditaabstrataquandopossuiumoumaismtodosquenoforamimplementados(chamados mtodos virtuaispuros).Istosignificaquenopodemosinstanciarumobjetodestaclasse,masapenasde suasclassesderivadas,ondeestesmtodosseroimplementados.Continuemoscomnossoexemplo,emque temosumaclasseTShapeeumaclasseTBlock.VamosincluirasclassesTBalleTBarqueherdamde TShapetambm.Portanto,nonossoprograma,todoshapeouumbloco,ouumabola,ouumabarra,eque qualquerobjetoqueherdedaclasseTShapetenhaquepossuiromtododraw().Entodevemosdeclararo mtodo draw() de TShape como virtual puro, transformando a classe TShape em classe abstrata e forandosoassubclassesaimplementaremomtodo.Istofeitocolocando=0nolugardocorpodomtodo (indicandoqueomtodonopossuiimplementaonestaclasse)comoveremosaseguir: class TShape { public: . . . virtual void draw()=0; }; class TBlock : public TShape { 55

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

public: . . . void draw(); }; void TBlock::draw() { cout << Drawing a block << endl; } class TBall : public TShape { public: . . . void draw(); }; void TBall::draw() { cout << Drawing a ball << endl; } class TBar : public TShape { public: . . . void draw(); }; void TBar::draw() { cout << Drawing a bar << endl; } Comovimos,todasasclassesderivadasdeTShapedeveroimplementaromtododraw().

Herana mltipla
OC++permitequeumaclasseherdedevriasoutras,incorporandoosmembrosdasduasclasses.Aherana mltipla contestadaporalgunsprogramadores,poisistofacilitaoconflitoentreosmembrosdasclasses. Vejamoscomodeclaramosumaclassecomheranamltipla: class TScreenObjects : public TBall, public TBar, public TBlock { . . . };

56

CaptuloIVEngenhariadeSoftwareOrientadaaObjetos Portanto,aclasse TScreenObjects possuiosmembrosdetodasasclassesqueelaherda.Masoque acontecesechamarmosomtodo draw(),queexisteemtodasassuperclassesde TScreenObjects? Nestecaso,ocompiladorgerariaumerro,poisnosaberiadequeclassechamaromtodo.Umasoluoseria fazerumaheranaprivadadassuperclasses(deformaqueseusmembrosnoficassemvisveisapartirda subclasse)edefinirmtodosparachamaromtododraw()decadasuperclasse: class TScreenObjects : private TBall, private TBar, private TBlock { public: drawBall() { TBall::draw(); } drawBar() { TBar::draw(); } drawBlock() { TBlock::draw(); } }; Outroproblemaqueenfrentamoscomaheranamltipla que,quandocriamosumobjetodasubclasse, estamoscriandoumobjetointernodecadasuperclasse.Eseassuperclassesherdaremdeumamesmaclasse base?Serocriadosvriosobjetosinternosdaclassebase(notequeserocriadosvrios objetosinternos idnticos),equandochamarmosummtododestaclassebase,ocompiladornosaber dequaldosobjetos internoschamaromtodo.Pararesolveristo,asclassesdevemfazerumaheranavirtualdaclassebase,de formaqueumnicoobjetodaclassebasesercriado: class TBall : public virtual TShape { . . . }; class TBar : public virtual TShape { . . . }; class TBlock : public virtual TShape { . . . }; class TScreenObjects : private TBall, private TBar, private TBlock { . . . }; Usarheranavirtualeliminaoconflitodeusarmosclassesbasecompartilhadas.Maseseassuperclassesde TScreenObjectspossuremconstrutoresquepassemargumentosdistintosparaaclasseTShape?Como oprogramaspodecriarumobjetocompartilhadodaclasseTShape,oC++desativaapassagemautomtica deparmetros(cominicializadores)dasclassesintermediriasparaaclassebasevirtualenoseulugarchama oconstrutorpadrodestaclasse.Vejamosesteexemplo:

57

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

TScreenObjects(int x1, int y1, const char *pattern) : TBall(x1, y1, pattern), TBar(x1, y1, pattern), TBlock(x1, y1, pattern) {}; Nesteexemplo,osconstrutoresdasclassesTBall, TBar e TBlocknoteropermissoparapassaros argumentosparaaclasseTShape.Paraqueesteexemplofuncionecorretamente,devemoschamartambmo construtordaclasseTShape: TScreenObjects(int x1, int y1, const char *pattern) : TShape(x1, y1, screenObject), TBall(x1, y1, pattern), TBar(x1, y1, pattern), TBlock(x1, y1, pattern) {}; AssimgarantimosainicializaocorretadosobjetosdaclasseTScreenObjects.

Excees
Exceessoerrosdetempodeexecuo,ouseja,nosobugs(errosdalgicadoprograma),massimerros geradospelamanipulaodedadosinadequados(geralmentefornecidosporusurios).Vejamosumexemplo destetipodeerro: int main () { int num1, num2; cout << Digite dois nmeros: ; cin >> num1 >> num2; cout << A diviso do nmero << num1 << pelo nmero ; cout << num2 << << (num1/num2) << endl; return 0; } Nesteexemplo,apesardalgicaestarcorreta,poderamosterumerrodetempodeexecuo(runtimeerror) casoousurioinformasseovalorzeroparaosegundonmero. Paraestestiposdeproblema queexistemasexcees.Omecanismodeexcees nospermitetentar executar(try)umdeterminadocdigo,casoocdigonopossaserexecutadolanamos(throw)uma exceoquesercapturada(catch)etratadaemoutrapartedocdigo.Vejamoscomoistofunciona: int main () { int num1, num2; cout << Digite dois nmeros: ; cin >> num1 >> num2; try {

if (num2 == 0) { throw string(Erro: diviso por zero.); } cout << A diviso do nmero << num1 << pelo nmero ; cout << num2 << << (num1/num2) << endl;

58

CaptuloIVEngenhariadeSoftwareOrientadaaObjetos } catch(string str) { cout << str << endl; } return 0; } Nocdigoacima,apartesensvel(ondepodeocorrerumaexceo), colocadadentrodeumblocotry. Casohajaumerro,lanamosumaexceocom throw,eofluxodoprogramaser desviadoparaforado bloco try.Apartirdestemomento,oprogramair procurarumbloco catch quecaptureumaexceodo mesmo tipo que a lanada (no nosso caso string). Caso no encontre, passa o fluxo do programa funo/mtodoquechamouocdigoquelanouaexceo,subindopelapilhadechamadasdefunes( call stack)atafunomain.Senafunomaintambmnohouverumbloco catchparaestetipodeexceo,o programaencerrado. Comovoc j deveterpercebido,podemoslanarumaexceodequalquertipodedado(inclusiveclasses especficasparatratamentodeexcees,comcdigoemensagensdeerro,etc..).OANSI/ISOC++define umaclassedeexceopadrochamada exception.Estaclassepossuiummtodoconstantechamado what()queretornaumconst char*contendoumamensagemdeerrodaexceo.Portanto,podemos criarnossasclassesdeexceoherdandodaclasse exceptionesobrescrevendoomtodowhat()para queexibaamensagemdeerroadequada.Vejamosumexemplo: class TDivideByZeroException : public exception { private: char *msg; public: const char *what() const {return msg;} TDivideByZeroException() {msg = Erro: diviso por zero.;} }; int main () { int num1, num2; cout << Digite dois nmeros: ; cin >> num1 >> num2; try { if (num2 == 0) { throw TDivideByZeroException(); } cout << A diviso do nmero << num1 << pelo nmero ; cout << num2 << << (num1/num2) << endl;

} catch(exception &e) { cout << e.what() << endl; } return 0;

59

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

} Podemos observar que o bloco catch (exception &e){...} captura uma exceo do tipo exceptionbemcomotodasqueherdamdela,comoTDivideByZeroException. Mascomotratarexceesinesperadas?Porpadro,oprogramachamaafunounexpectedquandoencontra uma exceo que no capturada por nenhum bloco catch. Esta funo, por sua vez chama a funo terminatequechamaabort.Oarquivodecabealhoexceptionpossuiasfunesset_unexpectede set_terminate, para definir funes de tratamento de excees inesperadas. Podemos definir uma funo comset_unexpected eestafunopodelevantarumaexceoquepossasercapturada por algum bloco catch ou encerrar o programa, chamando terminate, exit ou abort. Isto uma forma de converterumaexceoinesperadaparaumaexceoquepossamostratar.Podemostambmutilizarafuno set_terminateparadefinirumafunoaserchamadaantesqueoprogramaterminedeformaanormal. Exemplo: void exitFunction() { cout << Antes de terminar, imprimo isto. << endl; exit(1); } int main () { set_terminate(exitFunction); try { throw string(Erro); } catch(float f){} } return 0;

Nestecaso,comoaexceonofoicapturada,oprogramaterminou,masafunoexitFunction()foi chamadaantes. Podemostambmcriarblocoscatchquecapturemliteralmentequalquercoisa.Istofeitodaseguinteforma: catch (...) { . . . } Assim,qualquerexceolevantadasercapturadaporestebloco.

60

CaptuloIVEngenhariadeSoftwareOrientadaaObjetos

Seo prtica: Utilizando herana


Nestaseoiremos incrementaronossojogoutilizandoheranadeclasses.Podemoscriarumaclasse abstrata,TShapequeagrupeosatributoscomuns sclassesTBall,TBlockeTBar.Estaclassetambmdeve teroconceitodedesenhvel,ouseja,todoobjetoquepreciseserdesenhadonatela,podeherdardeTShape eaclasseTScreenreceberumobjetoTShapenomtododedesenharobjetosnatela: TScreen TShape

TBall

TBar

TBlock

Podemos,pensandoanalogamente,verificartodoonossoprogramaembuscadegruposdeclassesquepodem sergeneralizadas,aumentandoareusabilidadedonossocdigo.

61

Captulo V

Recursos avanados do C++: RTTI e STL

CaptuloVRecursosavanadosdoC++:RTTIeSTL

A RTTI (runtime type information)


Comaintroduodopolimorfismoemtempodeexecuo(umponteiropodeapontarparaelementosdoseu tipoedostiposderivados),svezestornase tilsaberaqueclassepertenceoobjetoparaoqualoponteiro est apontando.Isto feitocomoselementosdaRTTI( runtimetypeinformationinformaesdetipoem tempodeexecuo)deC++.OscomponentesdaRTTIso: Ooperador dynamic_cast:fazocast entre um ponteirodotipobase para um ponteirodotipo derivado(senoforpossvel,retornaNULL). Ooperadortypeid:queretornainformaessobreotipodedadosespecificado. Aclassetype_info:armazenainformaessobreostiposdedadosretornadasportypeid.

NotequeparautilizaroselementosdaRTTIdeC++necessrioincluiroarquivodecabealhotypeinfo.

O operador dynamic_cast
Esteoperador utilizadoquandonecessitamosconverterumponteirodeumaclassebaseparaumaclasse derivada,parapoderutilizarosmembrosdaclassederivada.Istos possvel,seoponteirodaclassebase estiverapontandoparaumobjetodaclassederivada.Senoforocaso,ooperadorretornaNULL(ponteiro nulo).Vejamosumexemplo: int main() { TBall bola; TShape *shapePtr = &bola; TBall *ballPtr = NULL; ballPtr = dynamic_cast <TBall *> (shapePtr); if (ballPtr != NULL) { cout << cast realizado com suceso! << endl; } else { cout << no foi possvel realizar o cast! << endl; } return 0;

NotequeumponteirodotipoTShapepodeapontartantoparaumobjetoTShapequantoparaobjetosdas classesderivadas,comoTBall.Oqueooperadordynamic_castfaz utilizarasinformaesdetempode execuodecadatipoparasabersepossvelrealizarocast.

Utilizando o operador typeid e a classe type_info


Ooperador typeid utilizadoparaobterinformaesdeumdeterminadotipoemtempodeexecuo.Ele retornaumobjetodaclassetype_info,comasinformaesdotipo.Osmembrosdaclassetype_infovariam deacordocomocompilador(poisosfabricantesestosemprequerendoincrementarascapacidadesdos seuscompiladores).OANSI/ISOC++determinaqueestaclassedeveterumconstrutor,umconstrutorde cpia,umoperadordeatribuio,umdestrutoreummtodochamado name(),queretornaonomedotipo doobjeto.Vejamosumexemplo:

63

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

int main() { TBall bola; TShape *shapePtr = &bola; TBall *ballPtr = NULL; if (typeid(*shapePtr) == typeid(TBall)) { cout << cast dinmico pode ser realizado! << endl; ballPtr = dynamic_cast <TBall *> (shapePtr); } else { cout << cast dinmico no pode ser realizado! << endl; } cout << o tipo do objeto apontado por shapePtr ; cout << typeid(*shapePtr).name() << endl; } return 0;

Neste caso, comparamos o tipo do objeto apontado por shapePtr com o tipo TBall, para nos certificarmosqueshapePtrapontaparaumobjetodotipoTBall,antesdefazerocastdinmico.Nofim do programa exibimos o nome do tipo do objeto apontado por shapePtr, que TBall (em alguns compiladoresexisteumavariaodestenome,evocpoderiaver4TBall,porexemplo).

64

CaptuloVRecursosavanadosdoC++:RTTIeSTL

A STL (standard template library)


Noscaptulosanteriores,vimoscomocriarclassestemplate,reutilizandoalgoritmoscomdiversostiposde dados.Almdepermitirousodeclassestemplate,oC++ofereceumconjuntodeclassestemplatejprontas paraseremutilizadaspelosprogramadores.Esteconjuntodeclassestemplate chamadodeSTL(standard templatelibrarybibliotecademodelospadro).ASTLfazpartedoANSI/ISOC++,deformaquetodo compiladorquedeseje estar deacordocom oC++padroANSI/ISO,dever darsuporte STLnasua totalidade,emboraistosejadifcildeacontecer. ASTLdivididaemquatrogruposdeclasses: Contineres:classesutilizadasparaarmazenaremanipularconjuntosdeobjetos. Iteradores:ponteirosespeciaisparaoscontineresdaSTL,quenospermitempercorrerosdadosdo continer. Algoritmos:conjuntodefunesquepodemosaplicaraoscontineresdaSTL. Objetosfuno:podemospersonalizarocomportamentodealgunsalgoritmosdaSTL,utilizando objetosfuno,oufunctores.

VeremosagoracadaumdosgruposdeelementosdaSTLdetalhadamente.

Contineres da STL
A STL do C++ possui onze contineres. Antes de conheclos, veremos os tipos comuns a todos os contineres,quesoutilizadosparacriarnossasvariveis(nalistaabaixo,continerrepresentaonomedo continer): continer::value_type:retornaotipodoelementodocontiner. continer::reference:retornaumarefernciaparaocontiner.equivalenteaT&. continer::const_reference : retorna uma referncia constante para o continer. equivalenteaconst T&. continer::iterator:otipodoiteratordocontiner.Umiterator umageneralizaopara T*. continer::const_iterator:otipodoiteratorconstantedocontiner.umageneralizao paraconst T*. continer::difference_type :umtipointeirocomsinalquerepresentaadistnciaentre iteradores. continer::size_type :umtipointeirosemsinalquerepresentaotamanhodeobjetosde dados,nmerodeelementosendices.

Almdestestipos,existemumconjuntodemtodosquesocomunsatodososcontineres(excetobitset)e seromostradosabaixo: begin:retornaumiteradorparaoprimeiroelementodocontiner. end:retornaumiteradorparaoelementoapsoltimo,docontiner. rbegin:retornaumiteradorreversoparaoprimeiroelementodocontiner. rend:retornaumiteradorreversoparaoelementoapsoltimo,docontiner. size:retornaonmerodeelementosdocontiner. maxsize:retornaotamanhomximodocontiner. empty:retornatrueseocontinerestivervazio. swap:permutaocontedodedoiscontineres. Operadorescondicionais==, !=, <, >, <= e >=:utilizadosparacomparardoiscontineres.

65

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

AgoraqueconhecemosumpoucodoscontineresdaSTL,veremoscadaumdetalhadamente.Abaixosegue umalistacomonome,descrio,interfaceeoarquivodecabealhoassociadoacadacontiner: vector Descrio Arquivodecabealho Interface

Representaumarrayunidimensional.Aprincipalvantagemdeutilizareste continer,emvezdeumarray,quepodemosalteraroseutamanhofacilmente emtempodeexecuo. vector template <class T, class Allocator = allocator<T> > class vector { public: // Typedefs typedef T value_type; typedef Allocator allocator_type; typedef typenameAllocator::referencereference; typedeftypenameAllocator::const_reference const_reference; classiterator; classconst_iterator; typedeftypenameAllocator::size_typesize_type; typedeftypenameAllocator::difference_type difference_type; typedeftypenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypenamestd::reverse_iterator<constiterator> const_reverse_iterator; // Construtores/Cpia/Destrutores explicitvector(constAllocator&=Allocator()); explicitvector(size_type,constAllocator&= Allocator()); vector(size_type,constT&,constAllocator&= Allocator()); vector(constvector<T,Allocator>&); template<classInputIterator> vector(InputIterator,InputIterator, constAllocator&=Allocator()); ~vector(); vector<T,Allocator>&operator=(const vector<T,Allocator>&); template<classInputIterator> voidassign(InputIteratorfirst,InputIteratorlast); voidassign(size_type,const); allocator_typeget_allocator()const; // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const;

66

CaptuloVRecursosavanadosdoC++:RTTIeSTL reverse_iterator rend (); const_reverse_iterator rend () const; // Capacidade size_type size () const; size_type max_size () const; void resize (size_type); void resize (size_type, T); size_type capacity () const; bool empty () const; voidreserve(size_type); // Acesso aos elementos referenceoperator[](size_type); const_referenceoperator[](size_type)const; referenceat(size_type); const_referenceat(size_type)const; referencefront(); const_referencefront()const; referenceback(); const_referenceback()const; //Modificadores voidpush_back(constT&); voidpop_back(); iteratorinsert(iterator,constT&); voidinsert(iterator,size_type,constT&); template<classInputIterator> voidinsert(iterator,InputIterator,InputIterator); iteratorerase(iterator); iteratorerase(iterator,iterator); voidswap(vector<T,Allocator>&); voidclear() };

list Descrio

Arquivodecabealho Interface

Representaumalistaduplamenteencadeada.Devemosutilizarestecontiner quandonecessitamosdefreqentesinsereseremoesnomeiodalista,pois estecontinerofereceumtempodeacessoconstanteaoselementos,independente dotamanhodalista. list template<classT,classAllocator=allocator<T>> classlist { public: // typedefs classiterator; classconst_iterator; typedeftypenameAllocator::referencereference; typedeftypenameAllocator::const_reference const_reference; typedeftypenameAllocator::size_typesize_type; typedeftypenameAllocator::difference_type

67

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

difference_type; typedef T value_type; typedef Allocator allocator_type; typedef typenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypename std::reverse_iterator<const_iterator> const_reverse_iterator; // Construtores/Cpia/Destrutores explicitlist(constAllocator&=Allocator()); explicitlist(size_type); list(size_type,constT&,constAllocator&= Allocator()) template<classInputIterator>list(InputIterator, InputIterator,constAllocator&= Allocator()); list(constlist<T,Allocator>&x); ~list(); list<T,Allocator>&operator=(const list<T,Allocator>&); template<classInputIterator>voidassign (InputIterator,InputIterator); voidassign(size_typen,constT&); allocator_typegetallocator()const; // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const; reverse_iteratorrend(); const_reverse_iteratorrend()const; // Capacidade boolempty()const; size_typesize()const; size_typemax_size()const; voidresize(size_type); voidresize(size_type,T); // Acesso aos elementos referencefront(); const_referencefront()const; referenceback(); const_referenceback()const; // Modificadores voidpush_front(constT&); voidpop_front(); voidpush_back(constT&); voidpop_back();

68

CaptuloVRecursosavanadosdoC++:RTTIeSTL iterator insert (iterator, const T&); void insert (iterator, size_type, constT&); template<classInputIterator> voidinsert(iterator,InputIterator, InputIterator); iteratorerase(iterator); iteratorerase(iterator,iterator); voidswap(list<T,Allocator>&); voidclear(); // Operaes especiais voidsplice(iterator,list<T,Allocator>&); voidsplice(iterator,list<T,Allocator>&, iterator); voidsplice(iterator,list<T,Allocator>&, iterator,iterator); voidremove(constT&); template<classPredicate>voidremove_if (Predicate); voidunique(); template<classBinaryPredicate> voidunique(BinaryPredicate); voidmerge(list<T,Allocator>&); template<classCompare> voidmerge(list<T,Allocator>&,Compare); voidsort(); template<classCompare>voidsort(Compare); voidreverse(); };

deque Descrio

Arquivodecabealho Interface

Doinglsdoubleendedqueue,representaumafilacomdoisfinais,ouseja, podemosadicionarouremoverelementosemambasasextremidades.Possui operaesdeinseroeapagamentocomtempoconstanteparaoincioefinalda fila,masotempodeacessocrescelinearmentecomotamanhodafilaparaacessos aelementosdomeio. deque template<classT,classAllocator=allocator<T>> classdeque { public: //Typedefs classiterator; classconst_iterator; typedefTvalue_type; typedefAllocatorallocator_type; typedeftypename Allocator::referencereference; typedeftypename Allocator::const_referenceconst_reference; typedeftypename Allocator::size_typesize_type; typedeftypename Allocator::difference_typedifference_type; typedeftypename

69

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

std::reverse_iterator<iterator> reverse_iterator; typedef typename std::reverse_iterator<const_iterator> const_reverse_iterator; // Construtores/Cpia/Destrutores explicit deque (constAllocator&=Allocator()); explicitdeque(size_type); deque(size_type,constT&value, constAllocator&=Allocator()); deque(constdeque<T,Allocator>&); template<classInputIterator> deque(InputIterator,InputIterator, constAllocator&=Allocator()); ~deque(); deque<T,Allocator>&operator= (constdeque<T,Allocator>&); template<classInputIterator> voidassign(InputIterator,InputIterator); voidassign(size_type,constT&); allocator_typegetallocator()const; // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const; reverse_iteratorrend(); const_reverse_iteratorrend()const; //Capacidade size_typesize()const; size_typemax_size()const; voidresize(size_type); voidresize(size_type,T); boolempty()const; // Acesso aos elementos referenceoperator[](size_type); const_referenceoperator[](size_type)const; referenceat(size_type); const_referenceat(size_type)const; referencefront(); const_referencefront()const; referenceback(); const_referenceback()const; // Modificadores voidpush_front(constT&); voidpush_back(constT&); iteratorinsert(iterator,constT&); voidinsert(iterator,size_type,constT&);

70

CaptuloVRecursosavanadosdoC++:RTTIeSTL template <classInputIterator> voidinsert(iterator,InputIterator, InputIterator); voidpop_front(); voidpop_back(); iteratorerase(iterator); iteratorerase(iterator,iterator); voidswap(deque<T,Allocator>&); voidclear(); };

queue Descrio Arquivodecabealho Interface

Representaumafilaemquepodemosfazerinseresnoincioeremover elementosdofim.umaformarestritadocontinerdeque. Queue template<classT,classContainer=deque<T>> classqueue { public: // typedefs typedeftypenameContainer::value_typevalue_type; typedeftypenameContainer::size_typesize_type; typedefContainercontainer_type; // Construtores/Cpia/Destrutores explicitqueue(constContainer&=Container()); // Acesso boolempty()const; size_typesize()const; value_type&front(); constvalue_type&front()const; value_type&back(); constvalue_type&back()const; voidpush(constvalue_type&); voidpop(); };

priority_queue Descrio

Arquivodecabealho Interface

Representaumafiladeprioridade.Aordemdoselementosdeterminadapelo operadormenorque,<oupelocomparadorcompare.Istosignificaqueos objetosguardadosnestecontinerdevemteresteoperadorsobrecarregadoalmde umconstrutordecpia,destrutoreoperador=. queue template<classT,classContainer=vector<T>, classCompare=less<typename Container::value_type>> classpriority_queue { public: // typedefs typedeftypenameContainer::value_typevalue_type;

71

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

typedef typenameContainer::size_typesize_type; typedefContainercontainer_type; // Construct explicitpriority_queue(constCompare&=Compare(), constContainer&= Container()); template<classInputIterator> priority_queue(InputIteratorfirst, InputIteratorlast, constCompare&=Compare(), constContainer&=Container()); boolempty()const; size_typesize()const; constvalue_type&top()const; voidpush(constvalue_type&); voidpop(); };

stack Descrio Arquivodecabealho Interface

Representaumapilha,comoperaesparaempilhar,desempilhareverotopoda pilha. stack template<classT,classContainer=deque<T>> classstack { public: // typedefs typedeftypenameContainer::value_typevalue_type; typedeftypenameContainer::size_typesize_type; typedefContainercontainer_type; // Construtor explicitstack(constContainer&=Container()); // Acesso boolempty()const; size_typesize()const; value_type&top(); constvalue_type&top()const; voidpush(constvalue_type&); voidpop(); };

set Descrio Arquivodecabealho Interface

Representaumconjuntodeobjetos,semelhanteaumconjuntomatemtico,sendo quecadaelementodoconjuntodevesernico.Implementaasoperaescomuns sobreconjuntos,comounio,interseo,etc. set template<classKey,classCompare=less<Key>, classAllocator=allocator<Key>> classset { 72

CaptuloVRecursosavanadosdoC++:RTTIeSTL public: // typedefs typedef Key key_type; typedef Key value_type; typedef Compare key_compare; typedef Compare value_compare; typedef Allocator allocator_type; typedef typenameAllocator::referencereference; typedeftypenameAllocator::const_reference const_reference; classiterator; classconst_iterator; typedeftypenameAllocator::size_typesize_type; typedeftypenameAllocator::difference_type difference_type; typedeftypenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypenamestd::reverse_iterator<const_iterator> const_reverse_iterator; //Construtores/Cpia/Destrutor explicitset(constCompare&=Compare(), constAllocator&=Allocator()); template<classInputIterator> set(InputIterator,InputIterator, constCompare&=Compare(), constAllocator&=Allocator()); set(constset<Key,Compare,Allocator>&); ~set(); set<Key,Compare,Allocator>&operator= (constset<Key,Compare,Allocator>&); allocator_typeget_allocator()const; // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const; reverse_iteratorrend(); const_reverse_iteratorrend()const; // Capacidade boolempty()const; size_typesize()const; size_typemax_size()const; // Modificadores pair<iterator,bool>insert(constvalue_type&); iteratorinsert(iterator,constvalue_type&); template<classInputIterator> voidinsert(InputIterator,InputIterator); voiderase(iterator);

73

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

size_type erase (const key_type&); void erase (iterator, iterator); void swap (set<Key, Compare, Allocator>&); void clear (); // Observao de elementos key_compare key_comp () const; value_compare value_comp () const; // Operaes sobre conjuntos size_type count (const key_type&) const; pair<iterator,iterator>equal_range(constkey_type&) const; iteratorfind(constkey_type&)const; iteratorlower_bound(constkey_type&)const; iteratorupper_bound(constkey_type&)const; };

multiset Descrio Arquivodecabealho Interface

Ocontinermultisetrepresentaumconjunto(semelhanteaoset)emqueos elementosnoprecisamsernicos. set template<classKey,classCompare=less<Key>, classAllocator=allocator<Key>> classmultiset { public: // typedefs typedefKeykey_type; typedefKeyvalue_type; typedefComparekey_compare; typedefComparevalue_compare; typedefAllocatorallocator_type; typedeftypenameAllocator::referencereference; typedeftypename Allocator::const_referenceconst_reference; classiterator; classconst_iterator; typedeftypenameAllocator::size_typesize_type; typedeftypename Allocator::difference_typedifference_type; typedeftypenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypename std::reverse_iterator<const_iterator> const_reverse_iterator; // Construtores/Cpia/Destrutores explicitmultiset(constCompare&=Compare(), constAllocator&=Allocator()); template<classInputIterator> multiset(InputIterator,InputIterator,

74

CaptuloVRecursosavanadosdoC++:RTTIeSTL const Compare& = Compare(), const Allocator& = Allocator()); multiset (const multiset<Key, Compare, Allocator>&); ~multiset (); multiset<Key, Compare, Allocator>& operator= (constmultiset<Key, Compare,Allocator>&); // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const; reverse_iteratorrend(); const_reverse_iteratorrend()const; // Capacidade boolempty()const; size_typesize()const; size_typemax_size()const; // Modificadores iteratorinsert(constvalue_type&); iteratorinsert(iterator,constvalue_type&); template<classInputIterator> voidinsert(InputIterator,InputIterator); voiderase(iterator); size_typeerase(constkey_type&); voiderase(iterator,iterator); voidswap(multiset<Key,Compare,Allocator>&); voidclear(); // Observao de elementos key_comparekey_comp()const; value_comparevalue_comp()const; // Operaes sobre Multiset iteratorfind(constkey_type&)const; size_typecount(constkey_type&)const; iteratorlower_bound(constkey_type&)const; iteratorupper_bound(constkey_type&)const; pair<iterator,iterator>equal_range (constkey_type&)const; };

map Descrio Arquivodecabealho Interface

Estecontinerrepresentaummapa,associaochave/valoremqueseusaachave paraacessarovalorcorrespondente.Nestecontiner,cadachavedevesernica,de modoquenopodemosterchavesrepetidas. map template<classKey,classT,classCompare=less<Key>

75

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

class Allocator = allocator<pair<constKey, T>>> classmap { public: // typedefs typedefKeykey_type; typedeftypenameAllocator::pointerpointer; typedeftypenameAllocator::const_pointer const_pointer; typedefTmapped_type; typedefpair<constKey,T>value_type; typedefComparekey_compare; typedefAllocatorallocator_type; typedeftypenameAllocator::referencereference; typedeftypename Allocator::const_referenceconst_reference; classiterator; classconst_iterator; typedeftypename Allocator::size_typesize_type; typedeftypename Allocator::difference_typedifference_type; typedeftypenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypename std::reverse_iterator<const_iterator> const_reverse_iterator; classvalue_compare :publicbinary_function<value_type,value_type, bool> { friendclassmap<Key,T,Compare,Allocator>; protected: Comparecomp; value_compare(Comparec):comp(c){} public: booloperator()(constvalue_type&, constvalue_type&)const; }; // Construtores/Cpia/Destrutores explicitmap(constCompare&=Compare(), constAllocator&=Allocator()); template<classInputIterator> map(InputIterator,InputIterator, constCompare&=Compare(), constAllocator&=Allocator()); map(constmap<Key,T,Compare,Allocator>&); ~map(); map<Key,T,Compare,Allocator>& operator=(constmap<Key,T,Compare, Allocator>&); allocator_typeget_allocator()const;

76

CaptuloVRecursosavanadosdoC++:RTTIeSTL // Iterators iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const; // Capacidade bool empty() const; size_typesize()const; size_typemax_size()const; //Acessoaoselementos mapped_type&operator[](constkey_type&); // Modificadores pair<iterator,bool>insert(constvalue_type&); iteratorinsert(iterator,constvalue_type&); template<classInputIterator> voidinsert(InputIterator,InputIterator); voiderase(iterator); size_typeerase(constkey_type&); voiderase(iterator,iterator); voidswap(map<Key,T,Compare,Allocator>&); voidclear(); //Observaodeelementos key_comparekey_comp()const; value_comparevalue_comp()const; //Operaessobremap iteratorfind(constkey_value&); const_iteratorfind(constkey_value&)const; size_typecount(constkey_type&)const; iteratorlower_bound(constkey_type&); const_iteratorlower_bound(constkey_type&)const; iteratorupper_bound(constkey_type&); const_iteratorupper_bound(constkey_type&)const; pair<iterator,iterator>equal_range(const key_type&); pair<const_iterator,const_iterator> equal_range(constkey_type&)const; };

multimap Descrio Arquivodecabealho Interface

Ocontinermultimaprepresentaummapa,semelhanteaocontinermap,mas possibilitandooarmazenamentodemltiplosvaloresparaumamesmachave. map template<classKey,classT,classCompare= less<Key>,classAllocator=allocator<pair<constKey, T>>> 77

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

class multimap { public: // typedefs typedef Key key_type; typedef T mapped_type; typedef pair<const Key, T> value_type; typedef Compare key_compare; typedef Allocator allocator_type; typedef typenameAllocator::referencereference; typedeftypename Allocator::const_referenceconst_reference; classiterator; classconst_iterator; typedeftypenameAllocator::size_typesize_type; typedeftypename Allocator::difference_typedifference_type; typedeftypenamestd::reverse_iterator<iterator> reverse_iterator; typedeftypename std::reverse_iterator<const_iterator> const_reverse_iterator; classvalue_compare :publicbinary_function<value_type,value_type,bool> { friendclassmultimap<Key,T,Compare,Allocator>; protected: Comparecomp; value_compare(CompareC):comp(c){} public: booloperator()(constvalue_type&, constvalue_type&)const; }; // Construtores/Cpia/Destrutores explicitmultimap(constCompare&=Compare(), constAllocator&=Allocator()); template<classInputIterator> multimap(InputIterator,InputIterator, constCompare&=Compare(), constAllocator&=Allocator()); multimap(constmultimap<Key,T,Compare, Allocator>&); ~multimap(); multimap<Key,T,Compare,Allocator>&operator= (constmultimap<Key,T,Compare,Allocator>&); allocator_typeget_allocator()const; // Iterators iteratorbegin(); const_iteratorbegin()const; iteratorend(); const_iteratorend()const; reverse_iteratorrbegin(); const_reverse_iteratorrbegin()const; reverse_iteratorrend();

78

CaptuloVRecursosavanadosdoC++:RTTIeSTL const_reverse_iterator rend () const; // Capacidade bool empty () const; size_typesize()const; size_typemax_size()const; //Modificadores iteratorinsert(constvalue_type&); iteratorinsert(iterator,constvalue_type&); template<classInputIterator> voidinsert(InputIterator,InputIterator); voiderase(iterator); size_typeerase(constkey_type&); voiderase(iterator,iterator); voidswap(multimap<Key,T,Compare,Allocator>&); voidclear(); //Observaodeelementos key_comparekey_comp()const; value_comparevalue_comp()const; // Operaes sobre Multimap iteratorfind(constkey_type&); const_iteratorfind(constkey_type&)const; size_typecount(constkey_type&)const; iteratorlower_bound(constkey_type&); const_iteratorlower_bound(constkey_type&)const; iteratorupper_bound(constkey_type&); const_iteratorupper_bound(constkey_type&)const; pair<iterator,iterator>equal_range(const key_type&); pair<const_iterator,const_iterator> equal_range(constkey_type&)const; };

bitset Descrio Arquivodecabealho Interface

Estecontinerrepresentaumconjuntodebits(bitset),quepodemseracessados individualmentecomooperadorcolchetes,[].Ofereceoperaeslgicasbitabit bemcomomtodosdemanipulaodosbitsindividualmenteouemconjunto. bitset template<size_tN> classbitset { public: // bit reference classreference { friendclassbitset; public: ~reference(); reference&operator=(bool); reference&operator=(constreference&); booloperator~()const; 79

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

operator bool()const; reference&flip(); }; //Construtores bitset(); bitset(unsignedlong); template<classcharT,classtraits,classAllocator> explicitbitset(constbasic_string<charT,traits, Allocator>,typenamebasic_string <charT,traits,Allocator> ::size_type=0,typenamebasic_string <charT,traits,Allocator> ::size_type=basic_string<charT, traits,Allocator>::npos); bitset(constbitset<N>&); bitset<N>&operator=(constbitset<N>&); // Operadores bit-a-bit bitset<N>&operator&=(constbitset<N>&); bitset<N>&operator|=(constbitset<N>&); bitset<N>&operator^=(constbitset<N>&); bitset<N>&operator<<=(size_t); bitset<N>&operator>>=(size_t); // Set, Reset, Flip bitset<N>&set(); bitset<N>&set(size_t,int=1); bitset<N>&reset(); bitset<N>&reset(size_t); bitset<N>operator~()const; bitset<N>&flip(); bitset<N>&flip(size_t); // Acesso aos elementos referenceoperator[](size_t); unsignedlongto_ulong()const; template<classcharT,classtraits,classAllocator> basic_string<charT,traits,Allocator> to_string(); size_tcount()const; size_tsize()const; booloperator==(constbitset<N>&)const; booloperator!=(constbitset<N>&)const; booltest(size_t)const; boolany()const; boolnone()const; bitset<N>operator<<(size_t)const; bitset<N>operator>>(size_t)const; }; // Operadores no-membros template<size_tN>bitset<N> operator&(constbitset<N>&,constbitset<N>&); template<size_tN>bitset<N> operator|(constbitset<N>&,constbitset<N>&);

80

CaptuloVRecursosavanadosdoC++:RTTIeSTL template <size_t N> bitset<N> operator^ (constbitset<N>&,constbitset<N>&); template<size_tN>istream& operator>>(istream&,bitset<N>&); template<size_tN>ostream& operator<<(ostream&,constbitset<N>&); O modelo ato_ptr AbibliotecapadrodoC++possuiummodelodeponteiro, auto_ptr,queoferecedesalocaoautomtica damemriaquandooponetirosaidoescopo.Portanto, idealparautilizarmosponteiroslocaissemterque nospreocuparmosemestarliberandomemriaquandosairmosdoescopo.importantelembrarque,comoo ponteirochamaooperador delete automaticamente, nopodemos alocar arrays com auto_ptr,pois o operadorchamadodeleteenodelete[]. Abaixosegueumexemplodecdigoqueutilizaoauto_ptr: int main() { auto_ptr<TBlock> block; block = new TBlock(10, 20, ####); block->draw(); } A classe template valarray Aclassevalarrayummodelodeclasseprojetadoparaserutilizadocomvaloresnumricos.Semelhanteao continervector,valarrayotimizadaparapermitiraplicaroperaesefunesmatemticasaoarray,como mximodeeficincia.Vejamosumexemplodeuso: int main() { valarray<int> array1(10); valarray<int> array2(10); for(int i = 0; i<10; i++) { array1[i] = i; } array2 = array1 + 10; // soma 10 a cada elemento de array1 e // atribui a array2 array1 += array2; // soma cada elemento de array1 com array2

for(int i = 0; i<10; i++) { cout << array1[i] << ; } } importantesalientarqueapenasostiposnumricospodemserutilizadoscomvalarray,equeestaclasse templatetambmpossuiimplementaesdasprincipaisfunesmatemticas,comoseno,cosseno,etc.

81

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

Iteradores
ASTLdeC++possuiumconjuntodeponteirosgenricosutilizadosparamanipularosdadosdoscontiners. Damesmaformaqueousodecontineresnospermiteutilizarosalgoritmosindependentedotipodedados, ositeradoresgeneralizamousodosalgoritmos,independentedocontiner.Ousodeiteradoressemelhante aousodeponteirosdeformaqueocdigoabaixo: int nums[10]; int *ptr; for (int i=0, ptr = nums; ptr != nums+10; i++, ptr++) *ptr = i; Podeserescritodestaforma: vector<int> nums(10); vector<int>::iterator itr; for (int i=0, itr = nums.begin(); itr != nums.end(); i++, itr++) *itr = i; Ento, por que utilizar iteradores? Porque em contineres diferentes, operaes como se mover para o prximoelementocausamresultadosdiferentestambm.Ento,utilizamositeradorescomqualquerfuno STLsemnospreocuparmoscomotipodecontineremqueosdadosestoarmazenados,poisousodos iteradoresomesmo. VejamosalgunsiteradorespredefinidosdaSTL: iterator:iteradorpadro. ostream_iterator:iteradordemanipulaodefluxosostream,comocout. istream_iterator:iteradordemanipulaodefluxosistream,comocin. reverse_iterator:iteradorquepercorreosdadosemsentidoreverso. insert_iterator:iteradordeinsero. front_insert_iterator:insereelementosemumcontinerapartirdoincio. back_insert_iterator:insereelementosemumcontinerapartirdofim.

Algoritmos da STL
OsalgoritmosdaSTLtrabalhamjuntocomositeradoresparamanipularosdadosdoscontineresdaSTL. Comoositeradoressoidependentesdostiposdoscontineres,podemosaplicarosalgoritmosaositeradores de qualquer continer, pois os iteradores que se encarregaro de percorrer internamente os dados contineres.VejamososalgoritmosdaSTL: accumulate Descrio Arquivodecabealho Interface acumulavaloresdeoperaesmatemticassucessivas. numeric template <classInputIterator,classT> Taccumulate(InputIteratorfirst, InputIteratorlast, Tinit);

82

CaptuloVRecursosavanadosdoC++:RTTIeSTL template <classInputIterator, classT, classBinaryOperation> Taccumulate(InputIteratorfirst, InputIteratorlast, Tinit, BinaryOperationbinary_op);

copy Descrio Arquivodecabealho Interface

Copiadadosentrecontineres. algorithm template<classInputIterator,classOutputIterator> OutputIteratorcopy(InputIteratorfirst, InputIteratorlast, OutputIteratorresult); template<classBidirectionalIterator1, classBidirectionalIterator2> BidirectionalIterator2 copy_backward(BidirectionalIterator1first, BidirectionalIterator1last, BidirectionalIterator2result);

count e count_if Descrio Arquivodecabealho Interface

Contaonmerodeelementosdeumcontiner.Oalgoritmocount_ifcontaos elementosdocontinerquesatisfazemumpredicado. algorithm template<classInputIterator,classT>typename iterator_traits<InputIterator>::difference_type count(InputIteratorfirst,InputIteratorlast, constT&value); template<classInputIterator,classT,classSize> voidcount(InputIteratorfirst,InputIteratorlast, constT&value,Size&n); template<classInputIterator,classPredicate>typename iterator_traits<InputIterator>::difference_type count_if(InputIteratorfirst,InputIterator last,Predicatepred); template<classInputIterator,classPredicate, classSize>voidcount_if(InputIterator first,InputIteratorlast,Predicatepred, Size&n);

equal Descrio Arquivodecabealho Interface

Comparaoselementosdedoiscontineresdentrodeumafaixadelimitadapelos iteradoresfirstelast. algorithm template<classInputIterator1,classInputIterator2> boolequal(InputIterator1first1,InputIterator1 last1,InputIterator2first2); template<classInputIterator1,classInputIterator2, classBinaryPredicate>

83

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryPredicate binary_pred); find Descrio Arquivodecabealho Interface

Procuraporumdeterminadovalornocontinereretornasuaprimeiraocorrncia. Senoencontrar,retornaoiteratorlast. algorithm template <classInputIterator,classT> InputIteratorfind(InputIteratorfirst, InputIteratorlast,constT&value);

for_each Descrio Arquivodecabealho Interface

Aplicaumafunoatodososelementosdocontinernointervaloentrefirstelast. algorithm template<classInputIterator,classFunction> voidfor_each(InputIteratorfirst,InputIteratorlast, Functionf);

min_element e max_element Descrio Retornamumiteradorqueapontaparaomnimoeomximoelementodo continer,respectivamente. algorithm Arquivodecabealho template<classForwardIterator>ForwardIterator Interface min_element(ForwardIteratorfirst, ForwardIteratorlast); template<classForwardIterator,classCompare> InputIteratormin_element(ForwardIterator first,ForwardIteratorlast,Comparecomp); template<classForwardIterator>ForwardIterator max_element(ForwardIteratorfirst, ForwardIteratorlast); template<classForwardIterator,classCompare> ForwardIteratormax_element(ForwardIterator first,ForwardIteratorlast,Comparecomp);

random_shuffle Descrio Arquivodecabealho Interface

Embaralhaaleatoriamenteoselementosdentrodointervalodeitaradoresfirste last,comdistribuiouniforme.Poderecebercomoargumentoumobjetofuno quegerenmerosaleatriosparaalteraradistribuio. algorithm template<classRandomAccessIterator> voidrandom_shuffle(RandomAccessIteratorfirst, RandomAccessIteratorlast); template<classRandomAccessIterator, classRandomNumberGenerator> voidrandom_shuffle(RandomAccessIteratorfirst, RandomAccessIteratorlast, RandomNumberGenerator&rand);

84

CaptuloVRecursosavanadosdoC++:RTTIeSTL

remove Descrio Arquivodecabealho Interface

Removeelementosdeumcontinerquesatisfazemacondioelemento==valor. algorithm template <classForwardIterator,classT> ForwardIteratorremove(ForwardIteratorfirst, ForwardIteratorlast,constT&value);

replace Descrio Arquivodecabealho Interface

Substituielementosdeumcontinerquesoiguaisaold_valuepor new_value. algorithm template<classForwardIterator,classT> voidreplace(ForwardIteratorfirst, ForwardIteratorlast,constT&old_value, constT&new_value);

reverse Descrio Arquivodecabealho Interface

Inverteaordemdoselementosdocontinerqueestonointervalo(first,last). algorithm template<classBidirectionalIterator> voidreverse(BidirectionalIteratorfirst, BidirectionalIteratorlast);

rotate Descrio Arquivodecabealho Interface

Rotacionaoselementosdosegmentoquevaidefirstatmiddle1comos elementosdosegmentodemiddleatlast.Oalgoritmorotate_copyretorna umacpiadocontinerrotacionado. algorithm template<classForwardIterator> voidrotate(ForwardIteratorfirst, ForwardIteratormiddle, ForwardIteratorlast); template<classForwardIterator,classOutputIterator> OutputIteratorrotate_copy(ForwardIteratorfirst, ForwardIteratormiddle, ForwardIteratorlast, OutputIteratorresult);

search Descrio

Arquivodecabealho Interface

searchprocuranointervalo(first1,last1)porumaseqnciaigualdo intervalo(first2,last2),enquantosearch_nretornaumiteradorparaa subseqnciadecountelementosquesoiguaisavalue.Podemostambm especificarumpredicadoparaquesejatestadonabusca. algorithm template<classForwardIterator1, classForwardIterator2>

85

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template <classForwardIterator1, classForwardIterator2, classBinaryPredicate> ForwardIterator1search(ForwardIterator1first1, ForwardIterator1last1, ForwardIterator2first2, ForwardIterator2last2, BinaryPredicatebinary_pred); template<classForwardIterator, classSize,classT> ForwardIteratorsearch_n(ForwardIteratorfirst, ForwardIteratorlast, Sizecount,constT&value); template<classForwardIterator, classSize,classT,classBinaryPredicate> ForwardIteratorsearch_n(ForwardIteratorfirst, ForwardIteratorlast, Sizecount,constT&value, BinaryPredicatepred)

sort Descrio Arquivodecabealho Interface

Ordenaoselementosdeumcontiner.Paracomparaoentreoselementosdo continer,podeserutilizadoooperadormenorque,<,ouumobjetofuno compare. algorithm template<classRandomAccessIterator> voidsort(RandomAccessIteratorfirst, RandomAccessIteratorlast); template<classRandomAccessIterator,classCompare> voidsort(RandomAccessIteratorfirst, RandomAccessIteratorlast,Comparecomp);

swap e swap_ranges Descrio swappermutaocontedodedoiscontineres,enquantoswap_ranges permutaoselementosdointervalo(first1,last1)comoselementosdeum intervalodomesmotamanhoqueiniciaemfirst2. algorithm Arquivodecabealho template<classT>voidswap(T&a,T&b); Interface template<classForwardIterator1, classForwardIterator2> ForwardIterator2swap_ranges(ForwardIterator1first1, ForwardIterator1last1, ForwardIterator2first2);

transform Descrio

Aplicaumafunoaumintervalodevaloresdeumcontiner.

86

CaptuloVRecursosavanadosdoC++:RTTIeSTL

Arquivodecabealho Interface

algorithm template <classInputIterator,classOutputIterator, classUnaryOperation>OutputIterator transform(InputIteratorfirst,InputIteratorlast, OutputIteratorresult,UnaryOperationop); template<classInputIterator1,classInputIterator2, classOutputIterator,classBinaryOperation> OutputIteratortransform(InputIterator1first1, InputIterator1last1,InputIterator2first2, OutputIteratorresult,BinaryOperationbinary_op);

unique e unique_copy Descrio Uniqueapagaosvaloresduplicadosconsecutivosemumcontiner.Unique_copy copiaoprimeiroelementodecadagrupodeelementosiguaisconsecutivospara result.Podemosutilizarumpredicadoparadeterminaraseleodosobjetos. algorithm Arquivodecabealho template<classForwardIterator>ForwardIterator Interface unique(ForwardIteratorfirst,ForwardIteratorlast); template<classForwardIterator,classBinaryPredicate> ForwardIteratorunique(ForwardIteratorfirst, ForwardIteratorlast, BinaryPredicatebinary_pred); template<classInputIterator,classOutputIterator> OutputIteratorunique_copy(InputIteratorfirst, InputIteratorlast, OutputIteratorresult); template<classInputIterator,classOutputIterator, classBinaryPredicate>OutputIterator unique_copy(InputIteratorfirst,InputIteratorlast, OutputIteratorresult, BinaryPredicatebinary_pred);

Objetos-funo
Alguns algoritmos daSTLrecebem classes especiais, quecontm funes para serem utilizadas com os algoritmosdaSTL.Sochamadosdeobjetosfuno,quepodempossuirfunesnormaiseponteirospara funes e objetos, sobrecarregando o operador parntesis, bastando para isto, definir um mtodo operator()(). Objetosfunopodemserdivididosnosseguintesgrupos: Geradores:objetosfunoquenorecebemargumentos. Funesunrias:objetosfunoquerecebemumargumento. Funesbinrias:objetosfunoquerecebemdoisargumentos. Predicados:funesunriasqueretornamumvalorboleano. Predicadosbinrios:funesbinriasqueretornamumvalorboleano.

87

DoCaoC++:umaabordagemdaEngenhariadeSoftware

TiagoBarros

ExistemvriosobjetosfunopredefinidosnaSTLdeC++.Parautilizlos,deveremosincluiroarquivode cabealho functional. Todas as operaes matemticas e lgicas simples possuem objetosfuno predefinidos,observeatabelaabaixo: Operador + * / % - (unrio) == != > < >= <= && || ! Objetofunocorrespondente plus minus multiplies divides modulus negate equal_to not_equal_to greater less greater_equal less_equal logical_and logical_or logical_not

Comistoencerramos anossavisogeral daSTL.Estamos prontos parautilizar todososrecursos desta poderosaferramentadoC++.

88