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

3
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

4
ndiceAnaltico

RecursosavanadosdoC++:RTTIeSTL......................................................................62

ARTTI(runtimetypeinformation)..................................................................................63
Ooperadordynamic_cast...................................................................................................................................63
Utilizandoooperadortypeideaclassetype_info..............................................................................................63

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

5
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

Comovocjdevesaber,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,quevocjdeveconhecer,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.Estestipossodefinidosatravsdaspalavraschavestruct,unioneenum(eposteriormente,como
veremos,class).

Estruturas

As estruturas de C++ funcionam como tipos compostos, em que se pode guardar diversas informaes
agrupadasemummesmonome.Porexemplo,paradefinirotipocompostobola,utilizamosstructdeacordo
comasintaxeabaixo:

struct TBall
{
int x;
int y;

7
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,queTColornoumtipodedadossimples,deformaquepodemoscriartiposdedadoscompostosa
partirdeoutrostiposcompostostambm.

Unies

Uma unio um tipo composto parecido com uma estrutura. A diferena que na unio, os diversos
membroscompartilhamamesmareadememria,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,nsatribumosumaconstantedotipocharuniovar.Posteriormente,acessamosaunio
varatravsdoseumembroi,dotiposhortint.ComoaletraArepresentadainternamenteatravsdoseu
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:

8
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(espaoreservadosvariveis)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
tempodeexecuoarmazenadanestarea.desumaimportnciaqueasvariveiscriadasnestarea
sejamdesalocadassemprequenoforemmaisserutilizadas.

Ligao

Aligao(lincagem)sereferecapacidadedeumitemserutilizadoemdiversosarquivosdeumprograma.
Variveisexternas(declaradasforadequalquerfuno)possuemtambmligaoexterna,oquesignificaque
elasficamdisponveisaqualquerarquivodomesmoprograma.Jasvariveisdeligaointernasesto
disponveisnoarquivoemqueforamcriadas.

Osconceitosvistosacimaestorelacionadosdeformanosistemtica,sendosvezesdifcildeseentender
claramente. Portanto, abaixo segue uma lista das possveis associaes entre classes de armazenamento,
escopoeligao:

Tipodavarivel Formadedeclarao Escopo Ligao


Variveisautomticas Declaradasdentrodeumbloco Local Interna
Variveisexternas Declaradasforadequalquerfuno Global Externa
Variveisexternasestticas Variveisexternasdeclaradascoma Global Interna
palavrachavestatic
Variveisexternasconstantes Variveisexternasdeclaradascoma Global Interna
palavrachaveconst
Variveisestticas Variveisautomticasdeclaradascoma Local Interna
palavrachavestatic

9
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),queumtamanhomenordoque
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,etambmquandoostiposnosocompatveismasaconversonecessria.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_ptrumponteiroconstantequandoatribumoseleaum
ponteironormal(nosepreocupe,veremosousodeponteirosmaisadiante):

char * ptr;
const char * const_ptr;
.
.
.
ptr = const_cast <char *> (const_ptr);

reinterpret_cast<tipo>(expresso):oreinterpret_castaformamaispoderosadeconversodetipos.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)eservistocomdetalhes
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,seublocodeinstruescorrespondenteserexecutado.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 aninhadosainstruo switch.Estainstruoutilizadapara


desviosmltiplos,deumaformamaissinttica.Asintaxedoswitch:

switch (expresso)
{
case valor1:
instruo1;
[break;]
case valor2:
instruo2;
[break;]
case valor3:
instruo3;
[break;]
.
.
.
default:
instruo_padro;
}

Casoainstruobreaknosejautilizada,oprogramacontinuarexecutandoasinstruesdoprximocase
atquehajaumbreakouqueacabeoblocoswitch.

Os laos while e do-while

Umlaowhileexecutaseublocodeinstruesenquantoasuaexpressoforavaliadacomoverdadeira(ou
diferentedezero).Possuiasseguintessintaxes:

while (expresso)
{
instrues;
}

ou

do
{
instrues;
} while (expresso);

Adiferena,quenolaowhilepuro,aexpressoavaliadaantesdeexecutarasinstrues,enquantono
lao dowhile asinstrues soexecutadas eaexpressoavaliadanofinal(portantoasinstrues so
executadaspelomenosumavez).

O lao for

12
CaptuloIEngenhariadeSoftwareEstruturada

Olaoforutilizadoquandodesejamosutilizarumndicenumrico,quesejaincrementado/decrementadoa
cadaiterao.Suasintaxe:

for (inicializao; expresso_de_teste; expresso_de_iterao)


{
instrues;
}

A inicializao executadaantesdecomearemasiteraesdolao.geralmenteondeinicializamosas
variveisdendicequeseroutilizadasnolao.Acadaiterao,aexpresso_de_testeavaliadaeolao
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
formadereferenciarumaposiodememriaatravsdoseuendereodireto.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.Istofeitoatravsdos
operadoresnewedelete.
Ooperadornewretornaumponteiroparaotipoespecificado,deformaque,sequisermoscriaruminteiroem
tempodeexecuo,devemosprocederdaseguinteforma:

int *ponteiro_para_int;
ponteiro_para_int = new int;

Agoravocentendeousodeponteiros,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, ouatquesejam desalocadas explicitamente.
Vejamosummauusodealocaodinmica:

for (int i=0; i < 1000; i++)


{
double *pointer;
pointer = new double;
pointer = i * 3.14159;
}

Nesteexemplo,avarivel pointer declaradadentrodocorpodo for,eporissocriadanareade


armazenamento automtico.Ento,noinciodaexecuo decada iterao, alocada memriapara esta
varivel.Depois,comooperadornew,alocadamemria(destaveznareadearmazenamentolivre)para
umavariveldotipodouble,eoendereoguardadoempointer,deformaapoderutilizarestareade
memria. No fim da execuo da iterao, a varivel pointer desalocada. Ento voc deve estar se
perguntando:oqueacontececomareaalocadapelooperadornew?Exatamente!Comonoexistenenhum
ponteiroquereferencieareaalocadaecomoelanofoiliberada,ficarocupandoespaoatofinaldo
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

Oexemploacimaexibir30comosada.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,[],pointersecomportarcomoum
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_inteiroseracrescidade1.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;

Istonosignificaqueoponteirospoderapontarparaconstantes.Narealidadeoqueestamosfazendo
informandoaocompiladorqueeledevetratarovalorparaoqualoponteiroapontacomoumaconstante,e
qualquer tentativa de tratlo de forma diferente causar erro de compilao. A importncia de utilizar
ponteirosdestaforma,nosprevenirmosdeerrosqueocorreriamseovalorfosseinadvertidamentealterado.

17
DoCaoC++:umaabordagemdaEngenhariadeSoftware TiagoBarros

Outromotivoquesponteirosparaconstantespodemapontarparaconstantes,osponteirosnormaisno
(istoumtantoquantobvio).
Apalavrachave const tambmpodeserutilizadaparadeclararponteirosconstantes(noteadiferenade
ponteirosparaconstantes).Comoeradeseesperarponteirosconstantesspoderoapontarparaumendereo
dememriaconstante,ouseja,nopodemalteraroendereocontidonele.Exemplo:

int um_inteiro;
int *const pointer = &um_inteiro;

Portanto,comovocjdevedesconfiar,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.Estadeclaraochamadadeprottipodeumafuno.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:
Otipoderetornodafunonarealidadeumponteiro,comojfoiexplicadoantes.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,oqueacontecequeaestruturapassadacopiadaparaumavarivel
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,mascomooqueretornadoumacpiadamesma,no
precisamosnospreocuparcomisto.

Ponteiros para funes

Comovimosanteriormente,podemosutilizarponteirosparaqualquertipodedados.Nestaseoveremosque
tambmpodemosutilizarponteirosparafunes.Comoasfunessodadoscompiladosarmazenadosna
memria,nadanosimpedequetenhamosumponteiroparaestesdados.Umponteiroparafunoapontapara
posiodememriaparaaqualoprogramatransferidoquandoafunochamada.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,todavezquefizermosumachamadafunodobro,ocdigo:2*numsercolocadoemseu
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,estamosespecificandoumvalorqueserutilizadocasono
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,ovalor1serutilizadonoseulugar.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,queaquantidadedeargumentosvariveis
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 << "--- Funcao sum com inteiros ---" << endl;
cout << "soma total: " << sum(num3, sum(num2, num1)) << endl;
cout << "num1: " << num1 << endl;
cout << "num2: " << num2 << endl;
cout << "num3: " << num3 << endl << endl;
cout << "--- Funcao sum com strings ---" << endl;
cout << "Strings: " << sum(str3, sum(str2, str1)) << endl;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;
cout << "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 Seqnciadecaracteres
Normal ESC[0m
Bold ESC[1m
Blink (piscando) ESC[5m
Reverso (cores do texto e fundo trocadas) ESC[7m
Mover para a posio 0,0 ESC[f
Mover para a posio x,y ESC[f ESC[yB ESC[xC
Apagaratela ESC[fESC[2J
Mudaracorparaatr,fg,bg(atr=0(normal)ou ESC[atr;fg;bgm
atr=1(highlight),fg=texto,bg=fundo)

Noteque atr e fg definemacordotextoenquanto bg defineacordefundo.Osvaloresque atr, fg e bg


podemassumirso:

25
DoCaoC++:umaabordagemdaEngenhariadeSoftware TiagoBarros

Cor Valordeatr Valordefg Valordebg


Preto 0 30 40
Vermelho 0 31 41
Verde 0 32 42
Marrom 0 33 43
Azul 0 34 44
Magenta 0 35 45
Ciano 0 36 46
Cinzaclaro 0 37 47
Cinzaescuro 1 30
Vermelhoclaro 1 31
Verdeclaro 1 32
Amarelo 1 33
Azulclaro 1 34
Magentaclaro 1 35
Cianoclaro 1 36
Branco 1 37

Agorajtemoscomomanipularasadadecaracteres natela.Vocdeveutilizaroarquivo 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

3
Informationhiddingumconceitodeengenhariadesoftwarequeconsisteemencapsularosdadosdeum
mdulodeformaqueestesssejamacessveisatravsdainterfacedomdulo.

28
CaptuloIIEngenhariadeSoftwareBaseadaemObjetos

Asinterfacesdosmdulossocriadasemarquivos.h.C++permiteacriaodeespaosdenomesseparados
paracadamdulo,paraquenosecorraoriscodeexistirconflitoentrenomesdedadosoufunesiguaisem
mdulosdiferentes.Istofeitoutilizandoseapalavrachavenamespace.
Comovimosanteriormente,podemosutilizaraspalavraschaveexternestaticparadefiniraligao(externa
ouinterna)dosdados.Veremosestesconceitosnaprticanaprximaseo.

Organizao dos arquivos

Abaixosegueummodelobsicodosarquivosdeummdulochamadomodulo1,comexplicaessobresuas
partes:

//-----------------------------------------------------------------
/* Arquivo modulo1.h */

#ifndef MODULO1_H // verifica se o arquivo j foi chamado


#define MODULO1_H // anteriormente para que no haja redefinio
// do mdulo

namespace modulo1 // 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 // inclui a interface do modulo 1

namespace modulo1 // 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(atenosdiferenasentre
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
ocorreriaseutilizssemosumtipoparaoqualafunonoadequada?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 responsvelpelasrotinasdedesenhoemanipulaodeimagensnatela.
game.cpp responsvelpelocontroleprincipaldojogo,pontuaoeentradadoteclado.
sprites.cpp responsvelpelocontroleemovimentaodoselementosdojogo(blocos,bolaebarra).
noid.cpp 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.Umaclasseummoldeapartirdoqualpodesecriartipos
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
espodeserchamadaapartirdela.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,eisumexemplodaclasseTBallcomtodososrequisitos
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.Comoodestrutorchamadopelaestruturainternadoprograma,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,estaaformacorretadeimplementao,poisaodefinirmosumaclasse
comocorpodosmtodosnadeclarao,ocompiladortrataistocomosefosseumadeclaraoimplcitade
mtodosinline,oquenodesejadoparatodososmtodos.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.Umaoutraformadecriarmtodosinlineutilizandoapalavraclaveinline,comoveremosa
seguir:

inline void TBall::setColor(TColor c)


{
color = c;
}

Adeclaraodomtodonadefiniodaclassecontinuasendofeitadamesmaforma.

Mtodos constantes

37
DoCaoC++:umaabordagemdaEngenhariadeSoftware TiagoBarros

Sedeclararmos umobjetodeumaclassecomoconstante,comousode const,spoderemoschamaros


mtodosdoobjetoqueforemconstantestambm,ouseja,ummtodoserchamadoconstantesignificaqueo
mtodonoalterarosatributosdoobjeto.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,elesspodemacessarosatributosestticosdaclasse.
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,quepassamoseretornamosoobjetoTBallporreferncia.Porqueisto
feito?VocdevelembrarqueoC++,aopassarumestruturaparaumafuno,passaaporvalor,fazendouma
cpiadaestruturanareadearmazenamentoautomtico.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.Istobastantetilquandotemosvriasclassesenoqueremoscriar
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

Acriaodeummtodofriendanlogadeumafunofriend,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,sequisssemosatribuiruminteiroaumobjetodotipoTBall
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>>.
Asobrecargadeoperadoressemelhantesobrecargademtodos,adiferenaqueutilizamosapalavra
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,quenestecasoonomedaclasseeopooperadoremsi,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);
}

Devemosobservarqueestecdigossobrecarregaooperador++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,ooperandonoumobjeto,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.Istonospermiteutilizarndicesdearray
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,poistypenamemuito
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,eimportanteperceberquepodemos(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.Omodificadorserveparaespecificarcomoasuperclasseservistadentroda
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,adiferenaque,parachamarmosmtodosda
superclassedentrodasubclasseutilizamos:nome_superclasse::metodo(parametros).

Mtodos virtuais: dynamic binding

53
DoCaoC++:umaabordagemdaEngenhariadeSoftware TiagoBarros

Comojvimos,possveltermosponteirosparaobjetosdeumaclasse.OC++tambmpermitequeponteiros
paraumasuperclasseapontemparaobjetosdeumaclassederivada,apesardenopoderacessarosmembros
especficosdesta.Esteprocesso,deumponteiropoderapontarparadiversosobjetosderivadosdistintos
chamadopolimorfismo.Entovocdeveestarpensando: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,oponteiroshapePtrdotipoTShapee,apesardepodermosapontarparaumobjetodo
tipo TBlock (afinal um TBlock um TShape), ao chamarmos um mtodo atravs do ponteiro, o
compiladorfarumaligaoesttica(staticbidingligaoemtempodecompilao)davarivelponteiro
comomtododesuaclasse.IstofarcomqueomtododaclasseTShapesejachamadoindependentemente
deparaqualobjetooponteiroaponte(afinal,emtempodecompilaonopossvelsaberocontedodo
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,estaremosassegurandoqueodestrutorcorretoserchamadoquandoumobjetodeumaclasse
derivadafordestrudo.

Classes abstratas

Umaclasseditaabstrataquandopossuiumoumaismtodosquenoforamimplementados(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
mltiplacontestadaporalgunsprogramadores,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(); }
};

Outroproblemaqueenfrentamoscomaheranamltiplaque,quandocriamosumobjetodasubclasse,
estamoscriandoumobjetointernodecadasuperclasse.Eseassuperclassesherdaremdeumamesmaclasse
base?Serocriadosvriosobjetosinternosdaclassebase(notequeserocriadosvrios objetosinternos
idnticos),equandochamarmosummtododestaclassebase,ocompiladornosaberdequaldosobjetos
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.
Paraestestiposdeproblemaqueexistemasexcees.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,eofluxodoprogramaserdesviadoparaforado
bloco try.Apartirdestemomento,oprogramairprocurarumbloco 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.Senafunomaintambmnohouverumblococatchparaestetipodeexceo,o
programaencerrado.
Comovocjdeveterpercebido,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,TShapequeagrupeosatributoscomunssclassesTBall,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),svezestornasetilsaberaqueclassepertenceoobjetoparaoqualoponteiro
estapontando.IstofeitocomoselementosdaRTTI(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

Esteoperadorutilizadoquandonecessitamosconverterumponteirodeumaclassebaseparaumaclasse
derivada,parapoderutilizarosmembrosdaclassederivada.Istospossvel,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_castfazutilizarasinformaesdetempode
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,umdestrutoreummtodochamadoname(),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.EsteconjuntodeclassestemplatechamadodeSTL(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.Umiteratorumageneralizaopara
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 Representaumarrayunidimensional.Aprincipalvantagemdeutilizareste
continer,emvezdeumarray,quepodemosalteraroseutamanhofacilmente
emtempodeexecuo.
Arquivodecabealho vector
Interface 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 Representaumalistaduplamenteencadeada.Devemosutilizarestecontiner
quandonecessitamosdefreqentesinsereseremoesnomeiodalista,pois
estecontinerofereceumtempodeacessoconstanteaoselementos,independente
dotamanhodalista.
Arquivodecabealho list
Interface 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 Doinglsdoubleendedqueue,representaumafilacomdoisfinais,ouseja,
podemosadicionarouremoverelementosemambasasextremidades.Possui
operaesdeinseroeapagamentocomtempoconstanteparaoincioefinalda
fila,masotempodeacessocrescelinearmentecomotamanhodafilaparaacessos
aelementosdomeio.
Arquivodecabealho deque
Interface 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 Representaumafilaemquepodemosfazerinseresnoincioeremover
elementosdofim.umaformarestritadocontinerdeque.
Arquivodecabealho Queue
Interface 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 Representaumafiladeprioridade.Aordemdoselementosdeterminadapelo
operadormenorque,<oupelocomparadorcompare.Istosignificaqueos
objetosguardadosnestecontinerdevemteresteoperadorsobrecarregadoalmde
umconstrutordecpia,destrutoreoperador=.
Arquivodecabealho queue
Interface 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 Representaumapilha,comoperaesparaempilhar,desempilhareverotopoda
pilha.
Arquivodecabealho stack
Interface 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 Representaumconjuntodeobjetos,semelhanteaumconjuntomatemtico,sendo
quecadaelementodoconjuntodevesernico.Implementaasoperaescomuns
sobreconjuntos,comounio,interseo,etc.
Arquivodecabealho set
Interface 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 Ocontinermultisetrepresentaumconjunto(semelhanteaoset)emqueos
elementosnoprecisamsernicos.
Arquivodecabealho set
Interface 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 Estecontinerrepresentaummapa,associaochave/valoremqueseusaachave
paraacessarovalorcorrespondente.Nestecontiner,cadachavedevesernica,de
modoquenopodemosterchavesrepetidas.
Arquivodecabealho map
Interface 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 Ocontinermultimaprepresentaummapa,semelhanteaocontinermap,mas
possibilitandooarmazenamentodemltiplosvaloresparaumamesmachave.
Arquivodecabealho map
Interface 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 Estecontinerrepresentaumconjuntodebits(bitset),quepodemseracessados
individualmentecomooperadorcolchetes,[].Ofereceoperaeslgicasbitabit
bemcomomtodosdemanipulaodosbitsindividualmenteouemconjunto.
Arquivodecabealho bitset
Interface 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 acumulavaloresdeoperaesmatemticassucessivas.

Arquivodecabealho numeric
Interface template <classInputIterator,classT>
Taccumulate(InputIteratorfirst,
InputIteratorlast,
Tinit);

82
CaptuloVRecursosavanadosdoC++:RTTIeSTL

template <classInputIterator,
classT,
classBinaryOperation>
Taccumulate(InputIteratorfirst,
InputIteratorlast,
Tinit,
BinaryOperationbinary_op);

copy
Descrio Copiadadosentrecontineres.

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

count e count_if
Descrio Contaonmerodeelementosdeumcontiner.Oalgoritmocount_ifcontaos
elementosdocontinerquesatisfazemumpredicado.
Arquivodecabealho algorithm
Interface 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 Comparaoselementosdedoiscontineresdentrodeumafaixadelimitadapelos
iteradoresfirstelast.
Arquivodecabealho algorithm
Interface 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 Procuraporumdeterminadovalornocontinereretornasuaprimeiraocorrncia.
Senoencontrar,retornaoiteratorlast.
Arquivodecabealho algorithm
Interface template <classInputIterator,classT>
InputIteratorfind(InputIteratorfirst,
InputIteratorlast,constT&value);

for_each
Descrio Aplicaumafunoatodososelementosdocontinernointervaloentrefirstelast.

Arquivodecabealho algorithm
Interface template<classInputIterator,classFunction>
voidfor_each(InputIteratorfirst,InputIteratorlast,
Functionf);

min_element e max_element
Descrio Retornamumiteradorqueapontaparaomnimoeomximoelementodo
continer,respectivamente.
Arquivodecabealho algorithm
Interface template<classForwardIterator>ForwardIterator
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 Embaralhaaleatoriamenteoselementosdentrodointervalodeitaradoresfirste
last,comdistribuiouniforme.Poderecebercomoargumentoumobjetofuno
quegerenmerosaleatriosparaalteraradistribuio.
Arquivodecabealho algorithm
Interface template<classRandomAccessIterator>
voidrandom_shuffle(RandomAccessIteratorfirst,
RandomAccessIteratorlast);
template<classRandomAccessIterator,
classRandomNumberGenerator>
voidrandom_shuffle(RandomAccessIteratorfirst,
RandomAccessIteratorlast,
RandomNumberGenerator&rand);

84
CaptuloVRecursosavanadosdoC++:RTTIeSTL

remove
Descrio Removeelementosdeumcontinerquesatisfazemacondioelemento==valor.

Arquivodecabealho algorithm
Interface template <classForwardIterator,classT>
ForwardIteratorremove(ForwardIteratorfirst,
ForwardIteratorlast,constT&value);

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

reverse
Descrio Inverteaordemdoselementosdocontinerqueestonointervalo(first,last).

Arquivodecabealho algorithm
Interface template<classBidirectionalIterator>
voidreverse(BidirectionalIteratorfirst,
BidirectionalIteratorlast);

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

search
Descrio searchprocuranointervalo(first1,last1)porumaseqnciaigualdo
intervalo(first2,last2),enquantosearch_nretornaumiteradorparaa
subseqnciadecountelementosquesoiguaisavalue.Podemostambm
especificarumpredicadoparaquesejatestadonabusca.
Arquivodecabealho algorithm
Interface 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 Ordenaoselementosdeumcontiner.Paracomparaoentreoselementosdo
continer,podeserutilizadoooperadormenorque,<,ouumobjetofuno
compare.
Arquivodecabealho algorithm
Interface 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.
Arquivodecabealho algorithm
Interface template<classT>voidswap(T&a,T&b);

template<classForwardIterator1,
classForwardIterator2>
ForwardIterator2swap_ranges(ForwardIterator1first1,
ForwardIterator1last1,
ForwardIterator2first2);

transform
Descrio Aplicaumafunoaumintervalodevaloresdeumcontiner.

86
CaptuloVRecursosavanadosdoC++:RTTIeSTL

Arquivodecabealho algorithm
Interface 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.
Arquivodecabealho algorithm
Interface template<classForwardIterator>ForwardIterator
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 Objetofunocorrespondente
+ plus
- minus
* multiplies
/ divides
% modulus
- (unrio) 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

Você também pode gostar