Engenharia De Sistemas Corlando/aulasesc.pdf · definição dos objetos de dados, que são...

127
1 Engenharia De Sistemas C Conteúdo Programático 1. Orientação a Objetos; 2. A Linguagem C++; 3. Especificação e Documentação de Software; 4. Qualidade de Software. Critério de Avaliação 1. Duas provas parciais; 2. Uma prova final; 3. Uma prova de reposição parcial; 4. Uma prova de reposição final; 5. A prova final valerá também como reposição; 6. Um trabalho contribuirá com 20% da nota parcial.

Transcript of Engenharia De Sistemas Corlando/aulasesc.pdf · definição dos objetos de dados, que são...

1

Engenharia De Sistemas C

Conteúdo Programático

1. Orientação a Objetos;

2. A Linguagem C++;

3. Especificação e Documentação de Software;

4. Qualidade de Software.

Critério de Avaliação

1. Duas provas parciais;

2. Uma prova final;

3. Uma prova de reposição parcial;

4. Uma prova de reposição final;

5. A prova final valerá também como reposição;

6. Um trabalho contribuirá com 20% da nota parcial.

2

1. Orientação a Objetos

1.1 Conceitos Teóricos

1.1.1 Conceitos básicos da orientação a objetos

A orientação a objetos possui três conceitos básicos: objetos, classes eherança.

Pode-se dizer que a orientação a objetos é uma volta à infância. Nojardim de infância, aprendemos a entender os seguintes conceitos:

• Objetos e suas propriedades: os objetos do mundo real possuemcaracterísticas estáticas e dinâmicas. Por exemplo, uma caneta éfina e comprida (características estáticas) e serve para escrever(característica dinâmica).

• Classes e seus membros: as classes são abstrações quecapturam características dos objetos. Objetos com característicassemelhantes são membros da mesma classe. Como exemplo,temos a classe dos seres vivos. O gato e o cachorro são seresvivos diferentes, mas possuem características semelhantes, logofazem parte da mesma classe (classe dos mamíferos).

• O todo e suas partes: um objeto pode ser composto por váriosoutros. Um objeto composto é considerado um objeto de nívelmais alto. Os objetos componentes de um outro objeto éconsiderado um objeto de nível mais baixo. Um exemplo da vidareal é um motor. Ele é um objeto composto de vários outrosobjetos menores (suas peças).

3

1.1.1.1. Objetos

Abstraindo, então, os objetos do mundo real, caminhamos para adefinição dos objetos de dados, que são compostos por duas partes:dados (propriedades estáticas) e de seus procedimentos (propriedadesdinâmicas). Dados e procedimentos são expressões comumenteusadas na análise estruturada. Essas expressões podem secorrelacionar respectivamente com atributos e métodos nametodologia orientada a objetos e com informação e consultas eatualizações nos bancos de dados relacionais.

(ref. Shlaer, S.; Mellor, S. J., “Object lifecycles - Modeling the word in states”,Yourdon Press Computing Series.)

Os objetos podem:

• ser criados e, por conseqüência, destruídos;

• se comunicar, via passagem de mensagens (síncronas eassíncronas) ou via chamada de rotinas (síncronas);

• servir de base para comunicação como conteúdo de mensagensou parâmetros de rotinas;

• ser compartilhado por outros objetos;

• ser protegidos.

1.1.1.2. Classe

Classe é o conjunto de objetos de mesma classificação. Podemosencarar uma classe como um módulo que encapsula suas operações.Uma das principais conseqüências desta modularização é o menorimpacto sofrido pelos sistemas em caso de manutenção. A classe é umtipo abstrato que engloba estado e operações. Dessa forma, as classesreúnem dados e funções, sendo tratadas de forma conjunta.

(Rumbaugh, J.; Blaha, M.; Premerlani, W.; Eddy, F.; Lorensen, W., “Modelagem eprojetos baseados em objetos”, ed. Campus.)

Os objetos só existem em tempo de execução. Já as classes existemfisicamente mesmo quando o programa não está executando.

4

Para entender o mundo real, o homem constantemente emprega trêsmétodos para organizar o seu pensamento:

• Diferenciação de experiências em objetos e seus atributos;

• Distinção entre objetos e suas partes;

• Formação e distinção entre diferentes classes de objetos.

Esses três métodos constam da teoria da classificação e têm grandeinfluência na reutilização de código.

(Coad, P.; Yourdon, E., “Object-oriented analisys”, Yourdon Press ComputingSeries.)

Dessa maneira, a base para a classificação consiste em abstrair objetosdo mundo real, organizando-os em classes conforme a equivalênciaentre eles.

Boa parte dessa classificação se dá na modelagem de sistemas. Ossistemas orientados a objetos são coleções de classes. Assim, a classeé o bloco básico para a construção de sistemas. Já o objeto é ainstância de uma classe, ou seja, os possíveis indivíduos que pertencemà classe.

5

Para definir uma classe, precisamos definir as propriedades comuns aosobjetos da classe. De uma forma mais computacional, é preciso definiros atributos e os métodos (mensagens) que condizem com a classe.

Como exemplo, podemos definir a classe pessoa. Atributos possíveispoderiam ser: primeiro nome: string ; último nome: string ; ano denascimento: number ; casado: boolean ; veste: roupa . Uma pessoapoderia ter serviços (métodos ou mensagens) como casar-se, vestir-seou dizer seu nome.

Podemos dividir as classes em dois tipos: classes abstratas econcretas .

As classes abstratas implementam características de suas subclasses.Já as classes concretas implementam métodos para suas subclasses.Por exemplo, a classe “animal” pode ser considerada uma classeabstrata, já que implementa características para suas subclasses, comotipo de respiração, alimentação peculiar, modo de locomoção, dentreoutras.

Então todas as suas subclasses (mamíferos, peixes etc) respiram, sealimentam, se locomovem etc. Já a classe “peixe” pode ser consideradauma classe concreta pois implementa métodos para suas subclasses,como por exemplo método “respirar” (água passa pelas brânquias, queretém o oxigênio). Esse método é utilizado por todas as subclasses de“peixe”, pois todos os peixes respiram dessa forma.

6

As classes podem se relacionar de duas maneiras: cliente/servidor eascendente/descendente .

Na primeira, uma classe depende de outra para executar alguma rotina.Isto se dá através de envio de mensagem. Por exemplo, uma classe queemite os contra-cheques dos funcionários de uma empresa precisa donome de cada um deles. Porém, para conseguir esses nomes, ela teráque enviar uma mensagem a cada uma das instâncias de funcionário,pedindo o nome do mesmo. Essa mensagem poderia se chamar“getNome”.

Já o relacionamento ascendente/descendente se dá através doconceito de herança, que será exposto posteriormente. Vamosaproveitar o exemplo anterior, onde a classe “funcionário” recebia amensagem “getNome”. Imaginem que a classe “funcionário” sejasubclasse da classe “pessoa”. Toda pessoa tem um nome. Espera-se,então, que o método “getNome” seja implementado na classe “pessoa” eherdado pela subclasse “funcionário”. Desta forma, “funcionário” executao método “getNome”, herdando-o da superclasse “pessoa”, e nãoenviando mensagem a ela.

1.1.1.3. Subclasse

As classes podem ser estruturadas hierarquicamente. Uma classe podepossuir uma ou mais subclasses e essas podem possuir outrassubclasses e assim sucessivamente.

A classe “mãe” da subclasse é conhecida como sua superclasse. Só sedefine uma subclasse quando existe uma característica particularadicionada às da superclasse.

7

Todo objeto pertencente a uma subclasse também pertence àsuperclasse. Porém o objeto na subclasse é caracterizado com maisdetalhes. Na superclasse ele é mais genérico. O número de objetos naclasse pode ser maior que a soma dos objetos das suas subclasses,porque podem haver objetos que só pertençam à classe (não serem“subclasseados”). Mas é possível também que a soma dos objetos dassubclasses seja maior que o número de objetos da superclasse. Istoporque um objeto pode pertencer ao mesmo tempo a duas subclassesde uma superclasse.

Vejamos o exemplo em que modelamos um sistema para uma empresadistribuidora de energia. Temos uma superclasse “parceiroComercial”que representa as empresas ou pessoas físicas que tem algumrelacionamento com a distribuidora de energia.

Esses parceiros comerciais podem ser consumidores de energia efornecedores. Isto está representado por duas subclasses: “fornecedor”e “consumidor”.

O caso mais típico é o de uma pessoa comum. Ela é “instanciada” naclasse “consumidor”, e por conseqüência na sua superclasse. Porém,existe um caso mais específico onde temos que “instanciar” umaempresa que fornece energia, como uma usina hidroelétrica. Aconteceque ela é fornecedora, mas também é consumidora de energia, já queseus prédios administrativos consomem energia. Logo podemos“instanciar” o mesmo objeto “parceiroComercial” como “fornecedor” e“consumidor”. Dessa forma, a distribuidora de energia tem controlesobre duas informações de um mesmo parceiro comercial (se ele é umbom fornecedor, mas um mau consumidor, por exemplo).

8

1.1.1.4. Hierarquia de classes

Um objeto em uma subclasse herda as propriedades definidas no nívelda classe a qual pertence a subclasse. A herança pode ser simples oumúltipla. Simples quando uma classe só é subclasse de uma únicaclasse. Múltipla quando ela pode ser subclasse de mais de uma classe,herdando as propriedades dessas. O “smalltalk” não suporta herançamúltipla.

Para podermos aproveitar melhor os recursos da herança, é importanteobservar características semelhantes em coisas completamentediferentes e não características diferentes em coisas muito parecidas.

9

1.1.1.5. Encapsulamento

Os métodos encapsulam o comportamento de um objeto. As mensagensconstituem a interface pública de um objeto. Somente através dasmensagens, é possível executar um método, isto é, acessar um objeto.Porém, os métodos não são “visíveis” externamente ao objeto, ou seja,não se pode ver o funcionamento interno dos métodos de um objeto.

A unidade de encapsulamento utilizada pela orientação a objetos é oobjeto. Isto significa que um objeto guarda dentro de si todas ascaracterísticas de alguma coisa do mundo real.

(Martin, J., “Principios de análise e projeto baseado em objetos”, ed. Campus.)

1.1.1.6. Abstração

É uma representação concisa de uma idéia ou de um objeto. Umaabstração nos ajuda a compreender algo complexo de forma simples,aumentando a nossa capacidade de lidar com a idéia ou com o objetoem questão.

10

1.1.2 Métodos para desenvolvimento orientado aobjetos

1.1.2.1. Visão Geral

Somente no final dos anos 80 os métodos de desenvolvimentoorientados a objetos começaram a ser divulgados. Uma defasagem de10 anos para as técnicas estruturadas.

Vários autores passaram a desenvolver métodos como Booch, Shlaer,Jacobison, Coad, Hood, Rumbaugh, dentre outros.

Várias dessas propostas ganharam aceitação. Algumas dessas,surgidas meados da década de 90, eram adaptações dos métodosestruturados, sendo bem percebidos pelas pessoas que já osconheciam.

Entretanto, esses métodos transitórios tinham um grande problema. Aousar a análise estruturada junto com o projeto e a programaçãoorientados a objetos, existia a necessidade de se fazer o mapeamentoda análise para o projeto.

11

Outras porém, eram propostas completamente novas, sendointeressantes para aqueles que não tinham experiência em nenhummétodo.

Neles, não existe necessidade de mapeamento, já que todas as fases,análise, projeto e programação são orientados a objetos.

Os métodos totalmente orientados a objetos nos ajudam nos seguintesitens, em cada fase do desenvolvimento:

ANÁLISE:

• identificar objetos;• identificar classes;• definir atributos;• definir métodos.

12

PROJETO:

• Especificar módulos para implementação das classes;• Especificar métodos.

PROGRAMAÇÃO:

• Implementar classes;• Implementar aplicação.

Ao longo dos anos 90, a tendência tem sido a de unificação dosmétodos existentes. Os pontos mais interessantes de cada um delestêm sido identificados em estudos conjuntos dos principais autores.

Esta convergência originou em 96 a UML (Unified ModelingLanguage ).

A UML é uma linguagem de modelagem. Ainda não é um método paradesenvolvimento e, portanto, não permite as definições de um processopara tanto.

13

1.1.2.2. Estratégia para desenvolvimento

A análise, o entendimento e a modelagem conceitual do negócio sãofundamentais para o sucesso dos sistemas.

Melhorias nos processos, adequação dos processos ao negócio, altonível de integração dos sistemas e de forma harmoniosa (semtransferências de arquivos), simplicidade do todo, alto nível dereutilização e facilidade para manutenção dependem fortemente de umaarquitetura baseada em um modelo conceitual do negócio.

O modelo conceitual do negócio captura as principais abstrações e seusrelacionamentos para o domínio do problema, isto é, os tipos essenciaisde objetos do negócio.

Já no modelo da análise é feito a determinação e o detalhamento dasprincipais abstrações e seus relacionamentos a serem tratados pelosistema.

Pode ocorrer também a identificação de novas abstrações nãopercebidas no modelo conceitual do negócio. Tanto o modelo conceitualdo negócio quanto o modelo da análise são modelos conceituaisvoltados para os usuários.

O modelo do projeto decide a forma de implementação das principaisabstrações e seus relacionamentos. Além disso, adiciona artefatos paraimplementação. É, na verdade, uma versão computacional do modeloda análise, sendo voltado para os analistas.

14

1.1.2.3. Processo de negócio

Um processo é uma ordenação específica de atividades de trabalho,através do tempo e do espaço, com um início e um fim e entradas esaídas bem definidas. Pode ser considerado uma estrutura de ação.

(Davenport, T., “Process Innovation: Reengineering Business Processes throughInformation Technology”, Harvard Business School Press)

Um processo de negócio é um conjunto de atividades internasrealizadas para servir a um cliente. O propósito de cada processo denegócio é oferecer a cada cliente o produto ou serviço correto.

(Jacobson, I.; Ericsson, M.; Jacobson, A., “Business Process Re-engeneering withObject Technology”, Addison-Wesley.)

A modelagem conceitual de objetos de um negócio considera umprocesso de negócio isoladamente. Está voltada para as necessidadesdo processo, e não para a integração. O produto final é o modeloconceitual dos tipos de objetos tratados pelo processo.

A modelagem conceitual de objetos de um sistema considera umsistema específico e está voltada para as necessidades do próprio e nãopara a integração.

O seu produto é o modelo conceitual dos tipos de objetos tratados pelosistema. Todas as consultorias, que promovem a reengenharia em umaempresa, deveriam gerar este modelo no final de seu trabalho.

A modelagem conceitual de objetos de uma área de negócio considerauma área de negócio da empresa. Utiliza os modelos dos processos daárea e está voltada para a integração e reutilização no nível da área.Produz o modelo conceitual dos tipos de objetos utilizados pela área.

Finalmente, a modelagem conceitual de objetos da empresa como umtodo considera o negócio global da empresa. Utiliza os modelos dasáreas de negócio e está voltada para a integração e reutilização no nívelda empresa. Produz o modelo conceiutal dos tipos de objetos utilizadospela empresa.

15

1.1.3 Técnicas de análise para orientação a objetos

1.1.3.1. Questões básicas

Quando analisamos um problema, algumas perguntas básicas nosocorrem. As técnicas de análise orientada a objetos exposta agorasugere um modelo como resposta a cada uma dessas perguntas. Aseguir, vemos cada uma delas relacionadas com as modelagempropostas.

• Quem vai utilizar o sistema e para fazer o quê?Resposta: Modelagem dos casos de uso.

• Que classes existem? O que define o estado dos objetos decada classe? Qual o comportamento esperado para os objetos decada classe? Quais os relacionamentos existentes entre cadaclasse?Resposta: Modelagem de classes.

• Como os estados dos objetos são afetados pelos eventosexternos e sua ordenação?Resposta: Modelagem do ciclo de vida dos objetos.

• Que mecanismos de colaboração entre objetos são necessáriospara dar a funcionalidade desejada para a aplicação?Resposta: Modelagem de mecanismos.

1.1.3.2. Modelagem de casos de uso

Apesar de ter nascido no contexto da orientação a objetos, amodelagem de casos de uso não tem nenhum vínculo com ela, podendoser utilizado em qualquer metodologia.

Um caso de uso modela uma perspectiva de utilização do sistema porparte de um tipo de usuário. Só é considerado como caso de uso, osque agregam um valor ao uso do sistema, isto é, tem que ser uma tarefacompleta e não parte de uma tarefa.

(Jacobson, I., “Object-oriented software engineering - A use case driven approach”,Addison-Wesley.)

16

Podemos considerar, como exemplos de casos de uso de um sistemade contas correntes de um banco, uma retirada de dinheiro de um caixaeletrônico, uma transferência de fundos, um depósito e a manutençãodo administrador do caixa eletrônico.

A ação do usuário se identificar não é considerado um caso de uso, poisnão agrega valor (não é uma tarefa completa).

Os usuários acessam um sistema interagindo com seus casos de uso.

Desse modo, um caso de uso modela um modo de utilização dosistema, expressa um requisito de uso a ser atendido, captura umaperspectiva de uso e é externamente observável por um usuário.

O conjunto de casos de uso de um sistema especifica todos os seusrequisitos de utilização, facilitando a medição de tempo dedesenvolvimento do sistema. Também modela o sistema, o seuambiente e como esses estão relacionados e descreve como o sistemaé visto externamente por seus usuários.

A modelagem é feita através de interações entre analistas e usuários edeve ser feita na fase inicial de especificação do sistema.

Um modelo de casos de uso é um gráfico que apresenta: atores, casosde uso e a interação entre eles.

17

Primeiro, identifica-se os atores, isto é, todos os elementos externos quese relacionam com o sistema. Depois os casos de uso e seusrelacionamentos.

A especificação deve prever as seqüências normais (o que o usuário faznormalmente), as seqüências alternativas (coisas a mais que se podefazer) e as excepcionais (situações especiais, como a falta de dinheirono caixa eletrônico).

A formalização da especificação pode ser feita através de pseudocódigoou diagramas de interação (diagrama de seqüência ou diagrama decolaboração).

18

A validação desse modelo passa pelos seguintes itens:

• Revisar e refinar, interativamente, o modelo;• Conceber, descrever e prototipar as interfaces a serem

utilizadas pelos usuários;• Quando aprovadas, liberar uma nova versão do modelo de

casos de uso.

As aplicações desse modelo estão no planejamento e organização dodesenvolvimento, planejamento e especificação dos testes eestruturação e desenvolvimento dos manuais de usuário.

Em resumo, o modelo de casos de uso representa tudo que os usuáriospodem fazer com o sistema. Dessa forma, esse modelo é válido comoum contrato entre os usuários e os analistas sobre o que poderá serfeito através do sistema.

(Jacobson, I., “Object-oriented software engineering - A use case driven approach”,Addison-Wesley.)

(Jacobson, I., “Basic use case modeling”, Addison-Wesley.)

1.1.3.3. Modelagem de classes

As técnicas de modelagem de classes persistem na identificação declasses e na identificação dos relacionamentos entre classes.

Além destas, existem mais duas técnicas complementares que nosauxiliam a fazer o modelo de classes:

• a percepção e modelagem do domínio do problema;• a modelagem de cada caso de uso.

Primeiramente, é interessante abstrair o problema e fazer o modelo declasses do todo.

19

Depois, fazer o modelo de classes para cada caso de uso e validar cadaum desses com o modelo do todo. A notação básica para classes é aseguinte:

20

O que podemos observar para melhor identificação de objetos e classes:

• As estruturas.

• Outros sistemas com o qual o nosso irá interagir, recebendo eenviando informações, controlando ou sendo controlado. Tambémoutros sistemas do mesmo domínio de problema, existentes naempresa, em outras empresas ou em bibliotecas de classes.

• Com que equipamentos o sistema irá interagir, como sensores, porexemplo.

• Eventos para os quais se deseja fazer planejamento, fazerprogramação, reter informações e analisar conseqüências.

• O papel exercido pelas pessoas que atuam no domínio do problema.

• Observar os locais, como posição geográfica e localização física.

• A organização da empresa (setores, departamentos, subsidiárias,filiais etc) e do negócio (segmentos, áreas de atuação etc).

Outra fonte de inspiração são os padrões (patterns ).

21

Padrões são soluções genéricas, em forma de modelo de classes, quesão catalogadas para serem utilizadas em problemas com domíniosparecidos.

Esta idéia vem da arquitetura, onde são utilizados vários padrões deplantas, conforme a necessidade do projeto. Os padrões são a grandesensação do momento, pois oferece grande chance de reutilização decódigo.

1.1.3.4. Modelagem do ciclo de vida dos objetos dasclasses

Existem três pontos básicos para este modelo: estados , eventos eoperações . Durante sua existência, um objeto passa por diferentesestados, de acordo com os eventos que ocorrem com ele, provocando aexecução de operações.

(Shlaer, S.; Mellor, S. J., “Object lifecycles - Modeling the word in states”, YourdonPress Computing Series.)

Por exemplo, para uma conta corrente temos:

ESTADOS EVENTOS OPERAÇÕESEm abertura Solicitação de abertura Abrir a contaOk Aceite do banco Colocar conta ativaTratando transação Retirada Tratar retirada

22

O comportamento de um sistema pode ser expresso em termos dacoordenação do comportamento de todos os objetos com os quais elelida.

O comportamento de um objeto pode ser estudado através da análisedo seu ciclo de vida. O modelo de estado representa o ciclo de vida deum objeto através dos seguintes conceitos: estado , evento e ação .

Durante sua existência, um objeto passa por alguns estados, de acordocom os eventos que ocorrem com ele. Por exemplo, um projeto passapelos seguintes estados: em estudo , aguardando aprovação ,aguardando alocação de recursos , em execução e concluído .

Durante a permanência de um objeto em um estado, ele segue umconjunto de regras: as leis físicas e as políticas operacionais queregulam o seu comportamento. O estado de um objeto representa oresultado acumulado de seu comportamento. Para certos estados, é útilapresentar as ações a ele associadas.

Um evento é um acontecimento que pode causar uma transição deestado. A partir de um mesmo estado, um evento só pode causar umatransição de estado. Por exemplo, um funcionário ao receber seu salárionão sofre alteração de seu estado. Já, ao entrar de férias, muda deestado.

No mundo real, existem acontecimentos envolvendo uma instância deum objeto. Um acontecimento possui dois aspectos relevantes: o fatoque aconteceu e com quem aconteceu.

Esses aspectos são formalizados através do conceito de evento, umsinal de controle que leva consigo o identificador da instância do objetoenvolvida no acontecimento. Um evento causa uma transição de umestado para outro ou do estado para ele mesmo.

A identificação de eventos nos ajuda a definir as fronteiras do sistema eassinalar responsabilidades comportamentais para as classes, já queum evento pode provocar a execução de alguma ação.

Ações são operações instantâneas. As atividades são operações nãoinstantâneas.

O ciclo de vida de um objeto pode ser analisado através de um gráficoque apresente:

23

• Os estados pelos quais o objeto passa durante sua vida;• Os eventos que provocam as mudanças de estado;• As ações a serem executadas.

Por que analisar o ciclo vida de um objeto?

• Para melhorar o entendimento do comportamento do objeto;• Para auxiliar a identificação dos métodos;• Para verificar se todos os atributos foram identificados;• Para refinar e complementar as restrições de integridade.

Para quais objetos devemos analisar o ciclo de vida?

• Para os que necessitamos melhorar a nossa compreensão;• Para os que tem tratamento diferenciado em função dos seus

estados;• Para os que são fundamentais para a compreensão do negócio

sendo modelado.

Para criar o modelo de estados, o analista deve:

1. Identificar os estados, identificar os eventos e produzir omodelo:

• analisar a cronologia dos fatos, funções e eventos que afetam oobjeto;

• analisar os atributos, identificando os que caracterizam adinâmica de estados do objeto.

2. Identificar os eventos de interesse:

• os que provocam alteração de atributos que caracterizam adinâmica de estado do objeto;

• os que são pré-requisitos para a ocorrência de outros eventos;• os que provocam e determinam a execução de métodos do

objeto.

24

3. Produzir o modelo:

• ordenar cronologicamente os estados;• associar os eventos aos estados;• desenhar o modelo.

25

1.1.3.5. Modelagem de mecanismos

Para cada caso de uso podem ocorrer diferentes cenários.

Cada cenário deve ser tratado por um mecanismo de colaboração entreobjetos. Existem duas técnicas equivalentes para modelar ummecanismo:

• Diagrama de seqüência (fluxo de mensagens entre objetos);• Diagrama de colaboração (integração entre objetos).

26

Modelados os mecanismos, podemos identificar:

• as responsabilidades de cada objeto em cada mecanismo;• as responsabilidades totais de cada objeto.

27

1.2 Linguagens Orientadas a Objetos

1.2.1 Mensagens

Possibilitam interação com os objetos

São compostas por: nome do objetonome do métodoparâmetros

menu_principal . seleciona (segunda_opcao) ;

↑ ↑ ↑

objeto mensagem parâmetro

Normalmente são bidirecionais

1.2.2 Programação OO com C++

Na prática de programação orientada a objetos estaremos atentos emnossos programas para pontos como:

• Compatibilidade, portabilidade.• Segurança.• Reusabilidade.• Facilidade de integração.

28

• Facilidade de extensão.• Eficiência.

1.2.2.1. Classes e Objetos

Uma classe é um tipo definido pelo usuário que contém o molde, aespecificação para os objetos, assim como o tipo inteiro contém o moldepara as variáveis declaradas como inteiros. A classe envolve, associa,funções e dados, controlando o acesso a estes, definí-la implica emespecificar os seus atributos (dados) e suas funções membro (código).

Um programa que utiliza uma interface controladora de um motorelétrico provavelmente definiria a classe motor. Os atributos destaclasse seriam: temperatura, velocidade, tensão aplicada. Estesprovavelmente seriam representados na classe por tipos como float oulong . As funções membro desta classe seriam funções para alterar avelocidade, ler a temperatura etc.

Um programa editor de textos definiria a classe parágrafo que teriacomo um de seus atributos uma string ou um vetor de strings , e comofunções membro, funções que operam sobre estas strings . Quando umnovo parágrafo é digitado no texto, o editor cria a partir da classeparágrafo um objeto contendo as informações particulares do novotexto. Isto se chama instanciação ou criação do objeto.

Classes podem ser declaradas usando a palavra reservada struct ou apalavra reservada class .

1.2.2.1.1. Especificando Uma Classe

Suponha um programa que controla um motor elétrico através de umasaída serial. A velocidade do motor é proporcional à tensão aplicada, eesta proporcional aos bits que vão para saída serial e passando por umconversor digital analógico.

Vamos abstrair todos esses detalhes por enquanto e modelar somente ainterface do motor como uma classe, a pergunta é que funções e quedados membro deve ter nossa classe, e que argumentos e valores deretorno devem ter essas funções membro:

29

Representação da velocidade:

A velocidade do motor será representada por um atributo, ou dadomembro, inteiro (int ). Usaremos a faixa de bits que precisarmos, caso ovalor de bits necessário não possa ser fornecido pelo tipo, usaremosentão o tipo long , isso depende do conversor digital analógico utilizadoe do compilador.

Representação da saída serial:

O motor precisa conhecer a sua saída serial, a sua ligação com o "motordo mundo real". Suponha uma representação em hexadecimal doatributo endereço de porta serial, um possível nome para o atributo:enderecomotor .

Alteração do valor da velocidade:

Internamente o usuário da classe motor pode desejar alterar avelocidade, cria-se então o método (em C++ função membro): voidaltera_velocidade(int novav); .

O código anterior corresponde ao cabeçalho da função membro, ela édefinida junto com a classe motor, associada a ela. O valor de retornoda função é void (valor vazio), poderia ser criado um valor de retorno(int) que indicasse se o valor de velocidade era permitido e foi alteradoou não era permitido e portanto não foi alterado.

Não faz sentido usar, chamar, esta função membro separada de umavariável do tipo motor, mas então porque na lista de argumentos não seencontra um motor?

Esse pensamento reflete a maneira de associar dados e código(funções) das linguagens procedurais. Em linguagens orientadas aobjetos o código e os dados são ligados de forma diferente, a própriadeclaração de um tipo definido pelo usuário já engloba as declaraçõesdas funções inerentes a este tipo.

1.2.2.1.2. Struct em C++

Objetos são instâncias de uma classe. Quando um objeto é criado eleprecisa ser inicializado, ou seja, para uma única classe Estudante degraduação , podemos ter vários objetos em um programa Estudante de

30

graduação Carlos , Identificação 941218 , Curso Computação ;Estudante de graduação Luiza , Identificação 943249 , CursoEngenharia Civil ...

A classe representa somente o molde para a criação dos objetos, essessim contém informação.

1.2.2.1.2.1. Atributos ou Dados Membro

Este exemplo declara uma struct e em seguida cria um objeto deste tipoem main alterando o conteúdo dessa variável. Uma struct é parecidacom um record de Pascal, a nossa representa um círculo com osatributos raio , posição x , posição y , que são coordenadas cartesianas.Note que este objeto não possui funções membro ainda.

#include <iostream.h>

struct circulo//struct que representa um circulo.

{float raio;float x;//posicoes em coordenadas cartesianasfloat y;};

void main(){circulo ac;//criacao de variavel , veja comentarios.ac.raio=10.0;//modificacao de conteudo (atributos) da structac.x=1.0;//colocando o circulo em uma posicao determinadaac.y=1.0;//colocando o circulo em uma posicao determinadacout << "Raio:"<<ac.raio <<endl;//verificacao dos atributos alterados.cout << "X:"<<ac.x << "\n"; // "\n"==endlcout << "Y:" <<ac.y<< endl;}

31

Resultado do programa

Raio:10X:1Y:1

Comentários

struct circulo//struct que representa um circulo.{float raio;float x;//posicoes em coordenadas cartesianasfloat y;};

Este código é a declaração da classe círculo, entre chaves vem osdados membro e as funções membro que não foram apresentadasainda.A sintaxe para criação de objetos da classe círculo (circulo ac; ) , porenquanto não difere da sintaxe para a criação de variáveis do tipo int .

O acesso aos dados membro deve ser feito usando o nome do objeto eo nome do dado membro, separados por um ponto: ac.raio=10.0; . Noteque raio sozinho não faz sentido no programa, precisa-se especificar deque objeto se deseja acessar o raio.

1.2.2.1.2.2. Métodos ou Funções Membro

A linguagem C++ permite que se acrescente funções de manipulação dastruct em sua declaração, juntando tudo numa só entidade que é umaclasse. Essas funções membro podem ter sua declaração (cabeçalho) eimplementação (código) dentro da struct ou só o cabeçalho (assinatura)na struct e a implementação, código, fora.

Este exemplo apresenta a primeira versão, o próximo a segunda versão(implementação fora da classe).

Essas funções compõem a interface da classe. A terminologia usadapara designá-las é bastante variada: funções membro, métodos etc.

32

Quando uma função membro é chamada, se diz que o objeto estárecebendo uma mensagem (para executar uma ação).

Um programa simples para testes sobre funções membro seria oseguinte:

#include <iostream.h>struct contador//conta ocorrencias de algo{int num;//numero do contadorvoid incrementa(void){num=num+1;};//incrementa contadorvoid comeca(void){num=0;};//comeca a contar};void main()//teste do contador{contador umcontador;umcontador.comeca();//nao esqueca dos parenteses, e uma funcao membro e//nao atributo!cout << umcontador.num << endl;umcontador.incrementa();cout << umcontador.num << endl;}

Resultado do programa

01

Comentários

O programa define um objeto que serve como contador, aimplementação representa a contagem no atributo num que é umnúmero inteiro. As funções membro são simples: incrementa adicionaum ao contador em qualquer estado e comeca inicia a contagem emzero.

A sintaxe para declaração de funções membro dentro de uma classe é a

33

mesma sintaxe de declaração de funções comuns: tipoderetornonomedafuncao(lista_de_argumentos) { /*codigo */ } .

A diferença é como a função membro está definida na classe, ela ganhaacesso direto aos dados membros, sem precisar usar o "ponto",exemplo um_objeto.dadomembro; . Lembre-se que as chamadas defunções membro já se referem a um objeto específico, embora elassejam definidas de uma forma geral para toda a classe.

A sintaxe de chamada ou acesso à funções membro é semelhante asintaxe de acesso aos dados membro com exceção dos parênteses quecontém a lista de argumentos da função, mesmo que a lista seja vaziaeles devem estar presentes: umcontador.incrementa(); .

Primeiro insere-se o nome do objeto e depois a chamada da função,estes são separados por um ponto. Não esquecer os parênteses naschamadas de funções membro.

#include <iostream.h> //para coutstruct circulo{float raio;float x;//atributo coordenada cartesiana xfloat y;//atributo coordenada cartesiana yvoid move(float dx,float dy)//função membro ou função membro move{x+=dx;//equivale a x=x+dx;y+=dy;}void mostra(void) //função membro mostra{cout << "Raio:"<<raio <<endl;cout << "X:"<<x << endl;cout << "Y:" <<y<< endl;}};void main(){circulo ac;

34

// * instanciação de um objeto circulo (criacao)ac.x=0.0;ac.y=0.0;ac.raio=10.0;ac.mostra();ac.move(1.0,1.0);ac.mostra();ac.x=100.0;ac.mostra();}

Resultado do programa

Raio:10X:0Y:0Raio:10X:1Y:1Raio:10X:100Y:1

Comentários

A função membro move altera as coordenadas do objeto. O objeto temsuas coordenadas x e y somadas com os argumentos dessa funçãomembro. Note que esta função membro representa uma maneira maissegura, clara, elegante de alterar as coordenadas do objeto do queacessá-las diretamente da seguinte forma: ac.x+=dx; . ac.y+=dy; .

Lembre-se que ac.x+=dx é uma abreviação para ac.x=ac.x+dx; .

É possível imaginar que as definições de funções membro ocupam umgrande espaço na representação interna dos objetos, mas lembre-seque elas são todas iguais para uma classe então basta manter paracada classe uma tabela de funções membro que é consultada nomomento da chamada . Os objetos só precisam ter uma referência paraesta tabela.

1.2.2.1.2.3. Funções Membro que Retornam Valores

Uma função membro, assim como uma função comum, pode retornar

35

qualquer tipo, inclusive os definidos pelo usuário. Sendo assim, suachamada no programa se aplica a qualquer lugar onde se espera umtipo igual ou equivalente ao tipo do seu valor de retorno, seja numa listade argumentos de outra função, em uma atribuição ou em um operadorcomo o cout << variavel; .

#include <iostream.h>struct contador//conta ocorrencias de algo{int num;//numero, posicao do contadorvoid incrementa(void){num=num+1;};//incrementa contadorvoid comeca(void){num=0;};//comeca a contar, "reset"int retorna_num(void) {return num;};};void main()//teste do contador{contador umcontador;umcontador.comeca();//nao esqueca dos parenteses, e uma funcao membro naodado!cout << umcontador.retorna_num() << endl;umcontador.incrementa();cout << umcontador.retorna_num() << endl;}

Resultado do programa

01

1.2.2.1.2.4. Funções Declaradas Externas a Classe, FunçõesMembro Chamando Funções Membro

Este exemplo apresenta a implementação, definição, das funções forada declaração da struct . Além disso introduz uma nova função chamadainicializa e funções float retorna_raio (void); e void altera_raio(float a) .

36

Inicializa coloca o ponto nas coordenadas passadas como seusargumentos.

Comentários

Em uma declaração de uma classe normalmente se coloca a declaraçãodas funções membro depois da declaração dos atributos, porémpodemos fazer intercalações ou adotar qualquer ordem que nosconvenha.

O programador não é obrigado a implementar as funções membrodentro da declaração da classe, basta defini-las e apresentar aimplementação em separado segundo a sintaxe (compilável) descrita aseguir:

#include <iostream.h>struct teste{int x;void altera_x(int v);//somente definicao implementacao vem depois, fora da//classe};void teste::altera_x(int v) { x=v;}//esta ja e a implementacao codigovoid main(){teste a;//instaciacao de um objetoa.altera_x(10);//chamada da funcao membro com valor 10 que sera//impresso a seguircout << a.x;//imprimindo o dado membro}

Resultado do programa anterior

10

37

Programa exemplo círculo, mais complexo:

#include <iostream.h>//para coutstruct circulo{float raio;float x;float y;void inicializa(float ax,float by,float cr);void altera_raio(float a);float retorna_raio(void);void move(float dx,float dy);void mostra(void);};void circulo::inicializa(float ax,float by,float cr){x=ax;y=by;raio=cr;}void circulo::altera_raio(float a){raio=a;}float circulo::retorna_raio(void){return raio;}void circulo::move(float dx,float dy){x+=dx;y+=dy;}void circulo::mostra(void){cout << "Raio:"<< retorna_raio() <<endl;cout << "X:"<<x << endl;cout << "Y:" <<y<< endl;}void main(){circulo ac;ac.inicializa(0.0,0.0,10.0);

38

ac.mostra();ac.move(1.0,1.0);ac.mostra();ac.x=100.0;ac.altera_raio(12.0);ac.mostra();}

Comentários

Observe que a função membro mostra chama a função membro floatretorna_raio(void) que é da mesma classe. Fica implícito da definiçãode mostra que retorna_raio() se aplica ao mesmo objeto instanciadoque recebeu a chamada de mostra , ou seja, não é necessário usar o .(ponto) na chamada de retorna_raio() .

Em programas maiores, chamadas aninhadas de funções membro sãobastante comuns.

Programação orientada a objetos e interfaces gráficas com ousuário

Existem libraries de classes que permitem o programador C++desenvolver aplicações para ambientes como o Microsoft Windowsregde uma maneira bastante abstrata, este é um exemplo claro de reuso decódigo, afinal o programador não precisa saber de detalhes da interfacepara programar nela.

Resultado do programa

Raio:10X:0Y:0Raio:10X:1Y:1Raio:12.0X:100.0Y:1

39

1.2.2.1.2.5. Algo Parecido em Uma Linguagem Procedural

Este tópico apresenta uma comparação entre C++ e Pascal, para talimplementou-se dois programas semelhantes. O programa C++ é oprograma círculo do tópico anterior: 1.2.2.1.2.4. O programa em Pascalvem a seguir:

PROGRAM Comparacao;{COMPARACAO COM UM PROGRAMA C++}TYPE Circulo=RECORDx:real;{COORDENADAS X E Y}y:real;r:real;{somente dados}END;var ac:circulo;leitura:integer;PROCEDURE Inicializa(varaltereme:Circulo;ax,by,cr:real);{COLOCA O CIRCULO EM DETERMINADA POSICAO}BEGINaltereme.x:=ax;altereme.y:=by;altereme.r:=cr;END;PROCEDURE Altera_Raio(var altereme:Circulo;ar:real);{ALTERA O RAIO DO CIRCULO}BEGINaltereme.r:=ar;END;FUNCTION Retorna_Raio(copieme:Circulo):real;BEGINRetorna_Raio:=copieme.r;END;PROCEDURE Move(var altereme:Circulo;dx,dy:real);{MODE AS COORDENADAS X E Y ACRESCENTANDO DX E DY}BEGINaltereme.x:=altereme.x+dx;altereme.y:=altereme.y+dy;END;PROCEDURE Mostra(copieme:Circulo);{MOSTRA O CIRCULO NA TELA}

40

BEGINwriteln('X:',copieme.x,' Y:',copieme.y,'R:',copieme.r);END;BEGIN{TESTES}Inicializa(ac,0.0,0.0,10.0);Mostra(ac);Move(ac,1.0,1.0);Mostra(ac);ac.x:=100.0;Altera_Raio(ac,12.0);Mostra(ac);read(leitura);END.

Resultado do programa

X: 0.0000000000E+00 Y: 0.0000000000E+00 R: 1.0000000000E+01X: 1.0000000000E+00 Y: 1.0000000000E+00 R: 1.0000000000E+01X: 1.0000000000E+02 Y: 1.0000000000E+00 R: 1.2000000000E+01

Comentários

C++

As classes em C++ englobam os dados membros e as funçõesmembros. Para executar uma ação sobre o objeto ou relativa a estebasta chamar uma função membro para este: ac.mostra(); .

A função membro não precisa de muitos argumentos, porque é própriada classe e portanto ganha acesso aos dados membro do objeto paraao qual ela foi associada:

float circulo::retorna_raio(void){ return raio; //tenho acesso direto a raio. }

Pascal

Em Pascal, os procedimentos e os dados são criados de formaseparada, mesmo que só tenham sentido juntos.

A junção entre os dados e procedimentos se dá através de passagemde parâmetros. No caso de uma linguagem procedural como Pascal, o

41

que normalmente é feito se assemelha ao código seguinte:Move(ac,1.0,1.0); . Ac nesse caso é um record , mas sem funçõesmembro, algo semelhante ao struct de C (não C++). Move, acessa osdados do record alterando os campos. O parâmetro é passado porreferência e o procedimento é definido a parte do registro, embora sósirva para aceitar argumentos do tipo Circulo e mover suascoordenadas.

Segurança

Em ambos os programas (Pascal, C++) o programador pode acessardiretamente os dados do tipo definido pelo usuário: ac.x:=100.0;(Pascal) ou ac.x=100.0; (C++).

Veremos em ENCAPSULAMENTO maneiras de proibir em C++ este tipode acesso direto ao dado membro, deixando este ser modificadosomente pelas funções membro. Isto nos garante maior segurança eliberdade pois podemos permitir ou não o acesso para cada dadomembro de acordo com nossa vontade.

Eficiência

Alguém pode argumentar que programas que usam bastante chamadasde funções podem se tornar pouco eficientes e que poderia ser melhoracessar diretamente os dados de um tipo definido pelo usuário ao invésde passar por todo o trabalho de cópia de argumentos, inserção dafunção na pilha etc.

Em verdade não se perde muito em eficiência, e além disso muitasvezes não se deseja permitir sempre o acesso direto aos dados de umtipo definido pelo usuário por razões de segurança. Nesse sentido C++oferece um recurso que permite ganhos em segurança sem perdermuito em eficiência.

1.2.2.1.2.6. Construtores

Construtores são funções membro especiais chamadas pelo sistema nomomento da criação de um objeto. Elas não possuem valor de retorno,porque você não pode chamar um construtor para um objeto.

42

Contrutores representam uma oportunidade de iniciar de formaorganizada os objetos, imagine se você esquece de iniciar corretamenteou o faz duas vezes etc.

Um construtor tem sempre o mesmo nome da classe e não pode serchamado pelo usuário desta. Para uma classe string , o construtor teriaa forma string(char* a); com o argumento char* especificado peloprogramador. Ele seria chamado automaticamente no momento dacriação, declaração de uma string :

string a("Texto");//alocacao estatica implica na chamada do construtora.mostra();//chamada de metodos estatica.

Existem variações sobre o tema que veremos mais tarde: Sobrecarga deconstrutor, copy constructor , como conseguir construtores virtuais,construtor de corpo vazio.

O exemplo a seguir é simples, semelhante aos anteriores, presteatenção na função membro com o mesmo nome que a classe (struct ),este é o construtor:

#include <iostream.h>struct ponto{float x;float y;public:ponto(float a,float b);//esse e o contrutor, note a ausencia do valor de//retornovoid mostra(void);void move(float dx,float dy);};ponto::ponto(float a,float b)//construtor tem sempre o nome da classe.{x=a;//incializando atributos da classey=b;//colocando a casa em ordem}

43

void ponto::mostra(void){cout << "X:" << x << " , Y:" << y << endl;}void ponto::move(float dx,float dy){x+=dx;y+=dy;}void main(){ponto ap(0.0,0.0);ap.mostra();ap.move(1.0,1.0);ap.mostra();}

Resultado do programa

X:0 , Y:0X:1 , Y:1

Comentários

Note que com a definição do construtor, você é obrigado a passar osargumentos deste no momento da criação do objeto.

1.2.2.1.2.7. Construtores e Agregação

O programa exemplo deste tópico cria uma classe reta com dois dadosmembro da classe ponto . C++ permite que no construtor da classe reta ,você chame os construtores dos atributos da classe ponto, se você nãoo fizer o compilador acusará um erro, pois os atributos ponto possuemconstrutores e eles precisam ser chamados para que a inicialização secomplete de modo correto para o conjunto.

Observe o código do construtor da classe reta usado no exemplo:

reta(float x1,float y1,float x2,float y2): p1(x1,y1),p2(x2,y2){//nada mais a fazer, os construtores de p1 e p2 ja//foram chamados}

44

p1(x1,y1) e p2(x2,y2) são as chamadas dos construtores da classeponto, elas devem ficar fora do corpo { } do construtor, nesta listaseparada por vírgulas você deve iniciar todos os atributos. Os tiposbásicos como int , float , etc podem ser iniciados nessa lista.

Por exemplo, se a classe reta tivesse um atributo inteiro de nomeidentificação, a lista poderia ser da seguinte forma:

reta(float x1,float y1,float x2,float y2):p1(x1,y1),p2(x2,y2), identificacao(10){//nada mais a fazer, os construtores de p1 e p2 ja//foram chamados}

seria como se a identificação tivesse um construtor que tem comoargumento seu valor.

reta (float x1,float y1,float x2,float y2):p1(x1,y1),p2(x2,y2){identificacao=10;//tambem pode, porque tipos básicos (int) em C++ não//são objetos portanto nao tem construtores}

Uma outra alternativa seria usar alocação dinâmica para os atributospontos que passariam a ser agora ponteiros para pontos . Nessecaso, o construtor da classe reta não precisaria criar os pontos.

Vamos ao exemplo, que novamente é semelhante aos anteriores, paraque o leitor preste atenção somente nas mudanças, que são osconceitos novos, sem ter que se esforçar muito para entender oprograma:

#include <iostream.h>struct ponto{float x;float y;//coordenadasponto(float a,float b){

45

x=a;y=b;}//construtorvoid move(float dx,float dy){ x+=dx; y+=dy; }//funcao membro comumvoid inicializa(float a,float b){ x=a; y=b; }void mostra(void){cout << "X:" << x << " , Y:" << y << endl;}};struct reta{ponto p1;ponto p2;reta(float x1,float y1,float x2,floaty2):p1(x1,y1),p2(x2,y2){//nada mais a fazer, os contrutores de p1 e p2 ja//foram chamados}void mostra(void);};void reta::mostra(void){p1.mostra();p2.mostra();}void main(){reta r1(1.0,1.0,10.0,10.0); //instanciacao da reta r1r1.mostra();}

Resultado do programa

X:1 , Y:1X:10 , Y:10

1.2.2.1.2.8. Destrutores

Análogos aos construtores, os destrutores também são funções membro

46

chamadas pelo sistema, só que elas são chamadas quando o objeto saide escopo ou em alocação dinâmica, tem seu ponteiro desalocado,ambas (construtor e destrutor) não possuem valor de retorno.

Você não pode chamar o destrutor, o que você faz é fornecer aocompilador o código a ser executado quando o objeto é destruído,apagado. Ao contrário dos construtores, os destrutores não temargumentos.

Os destrutores são muito úteis para limpar a casa quando um objetodeixa de ser usado, no escopo de uma função em que foi criado, oumesmo num bloco de código. Quando usados em conjunto comalocação dinâmica eles fornecem uma maneira muito prática e segurade organizar o uso do heap .

A importância dos destrutores em C++ é aumentada pela ausência degarbage collection ou coleta automática de lixo.

A sintaxe do destrutor é simples, ele também tem o mesmo nome daclasse só que precedido por ~. Ele não possui valor de retorno e seuargumento é void sempre:

~nomedaclasse(void) { /* Codigo do destrutor */ }

A seguir, um exemplo simples:

//destrutor de uma classe#include <iostream.h>struct contador{int num;contador(int n) {num=n;}//construtorvoid incrementa(void) {num+=1;}//funcao membro comum, pode ser chamada pelo usuario~contador(void){cout << "Contador destruido, valor:" << num <<endl;}//destrutor};void main(){contador minutos(0);minutos.incrementa();cout << minutos.num << endl;

47

{//inicio de novo bloco de codigocontador segundos(10);segundos.incrementa();cout << segundos.num <<endl;//fim de novo bloco de codigo}minutos.incrementa();}

Resultado do programa

111Contador destruido, valor:11Contador destruido, valor:2

Comentários

1. No escopo de main é criado o contador minutos com valorinicial==0 .

2. Minutos é incrementado, agora minutos.num==1 .3. O valor de num em minutos é impresso na tela.4. Um novo bloco de código é criado.5. Segundos é criado, instanciado como uma variável deste bloco de

código, o valor inicial de segundos é 10, para não confundir com oobjeto já criado.

6. Segundos é incrementado atingindo o valor 11.7. O valor de segundos é impresso na tela.8. Finalizamos o bloco de código em que foi criado segundos, agora

ele sai de escopo, é apagado, mas antes o sistema chamaautomaticamente o destrutor.

9. Voltando ao bloco de código de main() , minutos é novamenteincrementado.

10. Finalizamos main() , agora, todas as variáveis declaradas em main()saem de escopo, mas antes o sistema chama os destrutoresdaquelas que os possuem.

1.2.2.1.3. Encapsulamento com Class

Encapsulamento, data hiding . Neste tópico vamos falar das maneirasde restringir o acesso às declarações de uma classe, isto é feito em C++

48

através do uso das palavras reservadas public , private e protected .Friends também restringe o acesso a uma classe.

Tudo que foi feito até agora pode ser feito com a palavra class ao invésde struct , incluindo pequenas modificações. Mas porque usar class ?

A diferença é que os dados membro e funções membro de uma structsão acessíveis por default fora da struct enquanto que os atributos emétodos de uma classe não são acessíveis fora dela (main ) por default .Você nem deve ter se preocupado com isso porque usando struct daforma como usávamos, tudo ficava acessível.

Então como controlar o acesso de atributos e métodos em uma classe?Simples, através das palavras reservadas private , public e protected .

Public , private e protected podem ser vistos como qualificadores ,(specifiers ). Para facilitar a explicação suponha a seguintesdeclarações equivalentes de classes:

(Declaração 1)

class ponto {float x;//dados membrofloat y;

public://qualificadorvoid inicializa(float a, float b) {x=a; y=b;};//funcao membrovoid move(float dx, float dy) {x+=dx; y+=dy; };

};

A declaração 1 equivale totalmente à:

(Declaração 2)

class ponto {private:float x;float y;

49

public://qualificadorvoid inicializa(float a, float b) {x=a;y=b;};void move(float dx, float dy) {x+=dx;y+=dy; };

};

que equivale totalmente à:

(Declaração 3)

struct ponto {private://se eu nao colocar private eu perco o encapsulamento//em struct.float x;float y;

public://qualificadorvoid inicializa(float a, float b) {x=a;y=b;};void move(float dx, float dy) {x+=dx; y+=dy;};

};

Fica fácil entender essas declarações se você pensar no seguinte:esses qualificadores se aplicam aos métodos e atributos que vem apóseles, se houver então um outro qualificador, teremos agora um novo tipode acesso para os métodos declarados posteriormente.

Mas então porque as declarações são equivalentes? É porque oqualificador private é default para class , ou seja, se você nãoespecificar nada, até que se insira um qualificador, tudo o que fordeclarado numa classe é private . Já em struct , o que é default é oqualificador public .

Agora vamos entender o que é private e o que é public :

Vamos supor que você instanciou (criou) um objeto do tipo ponto em

50

seu programa:

ponto meu; //instanciacao

Segundo o uso de qualquer uma das definições da classe ponto dadasacima você não pode escrever no seu programa:

meu.x=5.0; //erro !

Como fazíamos nos exemplos anteriores, a não ser que x fossedeclarado depois de public na definição da classe o que não ocorreaqui. Mas você pode escrever x=5.0; na implementação (dentro) de ummétodo porque enquanto não for feito uso de herança, porque umafunção membro tem acesso a tudo que é de sua classe, veja o programaseguinte.

Você pode escrever: meu.move(5.0,5.0); , porque sua declaração(move ) está na parte public da classe. Já é possível perceber quepodem existir funções membro private também e essas só sãoacessíveis dentro do código da classe (outras funções membro).

1.2.2.1.3.1. Atributos Private , Funções Membro Public

Aplicando encapsulamento à classe ponto definida anteriormente.

#include <iostream.h>class ponto{private://nao precisaria por private, em class e defaultfloat x;//sao ocultos por defaultfloat y;//sao ocultos por defaultpublic://daqui em diante tudo e acessivel.void inicializa(float a,float b){ x=a; y=b; }//as funcoes de uma classe podem acessar os atributos//private dela mesma.void mostra(void){cout << "X:" << x << " , Y:" << y << endl;}};

51

void main(){ponto ap; //instanciacaoap.inicializa(0.0,0.0); //metodos publicap.mostra(); //metodos public}

Resultado do programa

X:0 , Y:0

Comentários

Este programa não deixa você tirar o ponto de (0,0) a não ser que sejachamada inicializa novamente. Fica claro que agora, encapsulando x ey precisamos de mais métodos para que a classe não tenha suafuncionalidade limitada.

Novamente: escrever ap.x=10; em main é um erro! Pois x estáqualificada como private .

1.2.2.1.3.2. Um Dado Membro é Public

Este programa é uma variante do anterior, a única diferença é que Y écolocado na parte public da definição da classe e é acessadodiretamente. Além disso, fornecemos aqui a função membro move , paraque você possa tirar o ponto do lugar.

#include <iostream.h>class ponto{float x;//sao ocultos por defaultpublic://daqui em diante tudo e acessivel.ponto(float a,float b);//construtor tambem pode ser inline ou naovoid mostra(void);void move(float dx,float dy);float y;//* Y nao e' mais ocultado};

52

ponto::ponto(float a,float b){x=a;y=b;}void ponto::mostra(void){cout << "X:" << x << " , Y:" << y << endl;}void ponto::move(float dx,float dy){x+=dx;y+=dy;}void main(){ponto ap(0.0,0.0);ap.mostra();ap.move(1.0,1.0);ap.mostra();ap.y=100.0;ap.mostra();}

Resultado do programa

X:0 , Y:0X:1 , Y:1X:1 , Y:100

Comentários

Observe que agora nada impede que você acesse diretamente y:ap.y=100.0 , porém ap.x=10.00 é um erro. Observe em que parte (área)da classe cada um desses dados membro foi declarado.

1.2.2.1.3.3. Compilando um Programa com Vários Arquivos

Normalmente os programas C++ são divididos em arquivos para melhororganização e encapsulamento, porém nada impede que o programadorfaça seu programa em um só arquivo. O programa exemplo da classeponto poderia ser dividido da seguinte forma:

53

//Arquivo 1 ponto.h, definicao para a classe ponto.class ponto{public://daqui em diante tudo e acessivel.void inicializa(float a,float b);void mostra(void);private:float x;//sao ocultos por defaultfloat y;//sao ocultos por default};

//Arquivo 2 , ponto.cpp , implementacao para a classe//ponto.#include <iostream.h>#include "ponto.h"void ponto::inicializa(float a,float b){ x=a; y=b; }//as funcoes de uma classe podem acessar os atributos//private dela mesma.void ponto::mostra(void){cout << "X:" << x << " , Y:" << y << endl;}

//Arquivo 3 . Programa principal: princ.cpp#include "ponto.h"void main(){ponto ap;//instanciacaoap.inicializa(0.0,0.0);//metodos publicap.mostra();//metodos public}

Os arquivos com extensão .h indicam header files . É costume deixarnesses arquivos somente a interface das classes e funções para que ousuário possa olhá-lo, como numa library .

54

No nosso caso o único arquivo header (.h) que temos é o ponto.h quedefine a classe ponto. Caso as dimensões de seu programa permitam,opte por separar cada classe em um header file , ou cada grupo deentidades (funções, classes) relacionadas.

O arquivo 2 ponto.cpp é um arquivo de implementação. Ele tem omesmo nome do arquivo ponto.h , embora isto não seja obrigatório. Émais organizado ir formando pares de arquivos header /implementation .

Este arquivo fornece o código para as operações da classe ponto, daí adeclaração: #include "ponto.h" . As aspas indicam que se trata de umarquivo criado pelo usuário e não uma library da linguagem como<iostream.h> , portanto o diretório onde se deve encontrar o arquivo édiferente do diretório onde se encontra <iostream.h> .

O arquivo 3 princ.cpp é o arquivo principal do programa, não é costumerelacionar seu nome com nomes de outros arquivos como no caso doarquivo 2 e o arquivo 1.

Observe que o arquivo 3 também declara #include "ponto.h" , istoporque ele faz uso das dos tipos definidos em "ponto.h" , porém"princ.cpp" não precisa declarar #include <iostream.h> porque estenão usa diretamente as definições de iostream em nenhum momento,caso "princ.cpp" o fizesse, o include <iostream> seria necessário.

Em alguns dos exemplos seguintes, serão encontradas as diretivas decompilação abaixo. Quando da elaboração de uma library para serusada por outros programadores, não se deve esquecer de usá-las:

#ifndef MLISTH_H#define MLISTH_H//Codigo#endif#ifndef MLISTH_H#define MLISTH_H//defina aqui seu header file.//perceba que "Nomearq.h" e escrito na diretiva como//NOMEARQ_H#endif

Essas diretivas servem para evitar que um header file seja incluídomais de uma vez no mesmo projeto.

55

Saber compilar programas divididos em vários arquivos é muitoimportante. Isto requer um certo esforço por parte do programador,porque os métodos podem variar de plataforma para plataforma.

1.2.2.1.4. Tipo Abstrato de Dados

Tipo abstrato de dados, TAD, se preocupa em proporcionar umaabstração sobre uma estrutura de dados em termos de uma interfacebem definida. São importantes os aspectos de encapsulamento, quemantém a integridade do objeto evitando acessos inesperados, e o fatode o código estar armazenado em um só lugar o que cria um programamodificável, legível, coeso.

Uma classe implementa um tipo abstrato de dados.

São exemplos de tipos abstratos de dados:

1. Uma árvore binária com as operações usuais de inserção, remoção,busca.

2. Uma representação para números racionais (numerador,denominador) que possua as operações aritméticas básicas eoutras de conversão de tipos.

3. Uma representação para ângulos na forma (Graus, Minutos,Segundos). Também com as operações relacionadas, bem como asoperações para converter para radianos, entre outras.

1.2.2.1.4.1. TAD Fração

Tipo abstrato de dados fração. Baseado no conceito de número racionaldo campo da matemática.

Resumo das operações matemáticas envolvidas:

• Simplificação de fração: (a/b)=( (a/mdc(a,b)) / (b/mdc(a,b)) ); ondemdc(a,b) retorna o máximo divisor comum de ab.

• Soma de fração: (a/b)+(c/d)=( (a.d+c.b) / b.d ) simplificada.

• Multiplicação de fração: (a/b) * (c/d)= ( (a*c) / (b*d) ) simplificada.

• Igualdade: (a/b)== (c/d) se a*d == b*c.

56

• Não igualdade: (a/b) != (c/d) se a*d != b*c

• Maior ou igual que: (a/b) >= (c/d) se a*d >= b*c

//header file para o TAD fracao.//File easyfra.hlong mdc(long n,long d);//maximo divisor comum metodo de Euclides.class fracao {private:long num;//numeradorlong den;//denominadorpublic:fracao(long t,long m);//construtor comumvoid simplifica(void);//divisao pelo mdc~fracao() { /* nao faz nada*/ }//Nao e preciso fazer nada.//operacoes matematicas basicasfracao soma (fracao j);fracao multiplicacao(fracao j);//operacoes de comparacaoint igual(fracao t);int diferente(fracao t);int maiorouigual(fracao t);//operacoes de input outputvoid mostra(void);//exibe fracao no videovoid cria(void);//pergunta ao usuario o valor da fracao//operacoes de conversao de tiposdouble convertedbl(void);//converte para doublelong convertelng(void);//converte para long};

//implementacao para a classe fracao.#include <iostream.h>

57

#include "easyfra.h"long mdc(long n,long d)//maximo divisor comum//metodo de Euclides +- 300 anos AC.{if (n<0) n=-n;if (d<0) d=-d;while (d!=0) {long r=n % d;//%=MOD=Resto da divisao inteira.n=d;d=r;}return n;}void fracao::simplifica(void){long commd;commd=mdc(num,den);//divisor comumnum=num/commd;den=den/commd;if (den<0) { den=-den; num=-num;};//move sinal para cima}fracao::fracao(long t,long m){num=(t);den=(m);simplifica(); //chamada para o mesmo objeto.}fracao fracao::soma(fracao j){fracao g((num*j.den)+(j.num*den),den*j.den);return g;}fracao fracao::multiplicacao(fracao j){fracao g(num*j.num,den*j.den);return g;}int fracao::igual(fracao t){return ((num*t.den)==(den*t.num));

58

//funciona bem mesmo para nao simplificada}int fracao::diferente(fracao t){return ((num*t.den)!=(den*t.num));}int fracao::maiorouigual(fracao t){return ((num*t.den)>=(t.num*den));}void fracao::mostra(void){cout << "(" << num << "/" << den << ")";}void fracao::cria(void){cout << "Numerador:";cin >> num;cout << "Denominador:";cin >> den;simplifica();}double fracao::convertedbl(void){double dbl;dbl=(double(num)/double(den));return dbl;}//conversao para longlong fracao::convertelng(void){long lng;lng=num/den;return lng;}

#include <iostream.h>#include "easyfra.h"//nossa definicao da classe#include <stdio.h>main(){fracao a(0,1),b(0,1);

59

cout << " Entre com fracao a: ";a.cria();a.mostra();cout << " Entre com fracao b: ";b.cria();b.mostra();fracao c(a.soma(b));//c(a+b)cout << endl << "c de a+b:";c.mostra();cout << endl << "a*b";c=a.multiplicacao(b);c.mostra();cout << endl << "a+b";c=a.soma(b);c.mostra();cout << endl << "a>=b";cout << a.maiorouigual(b);cout << endl << "a==b";cout << a.igual(b);cout << endl << "a!=b";cout << a.diferente(b);cout << endl << "long(a) ";cout << a.convertelng();cout << endl << "double(a) ";cout << a.convertedbl();return 0;}

Comentários

Observe o seguinte código usado no programa: fracao c(a.soma(b)); . Oresultado de a.soma(b) é uma fração, mas não criamos um construtorque recebe uma fração como argumento, como isso foi possível noprograma?

Simples, a linguagem oferece para as classes que você cria a cópia bit abit. Cuidado com o uso dessa cópia em conjunto com alocaçãodinâmica, objetos poderão ter cópias iguais de ponteiros, ou sejacompartilhar uso de posições na memória.

60

Resultado do programa

Entre com fracao a: Numerador:4Denominador:2(2/1) Entre com fracao b: Numerador:5Denominador:3(5/3)c de a+b:(11/3)a*b(10/3)a+b(11/3)a>=b1a==b0a!=b1long(a) 2double(a) 2

1.2.2.1.5. Considerações C++

1.2.2.1.5.1. Const

Este exemplo mostra o uso de funções const e sua importância para oencapsulamento. Const pode qualificar um parâmetro de função(assegurando que este não será modificado), uma função membro(assegurando que esta não modifica os dados membro de sua classe),ou uma instância de objeto/tipo (assegurando que este não serámodificado).

Os modos de qualificação descritos atuam em conjunto, para assegurarque um objeto const não será modificado, C++ só permite que sejamchamados para este objeto funções membro qualificadas como const .Const é também um qualificador (specifier ).

#include <iostream.h>#include <math.h>

//double sqrt(double x); de math.h retorna raiz//quadrada do numero//double pow(double x, double y); de math.h calcula x//a potencia de y

const float ZERO=0.0;class ponto

61

{private:float x;//sao ocultos por default nao precisaria private mas//e' bomfloat y;//sao ocultos por defaultpublic://daqui em diante tudo e acessivel em main.ponto(float a,float b){ x=a; y=b; }void mostra(void) const{cout << "X:" << x << " , Y:" << y << endl;}float distancia(const ponto hi) const{returnfloat(sqrt((pow(double(hi.x-x),2.0)+pow(double(hi.y-y),2.0)) ) );//teorema de Pitagoras}};void main(){ponto ap(3.0,4.0);//instanciacaoap.mostra();//funcoes membro publicconst ponto origem(ZERO,ZERO);//defino objeto constanteorigem.mostra();cout << "Distancia da origem:" <<origem.distancia(ap);}

Resultado do programa

X:3 , Y:4X:0 , Y:0Distancia da origem:5

62

Comentários

• Const qualificando instâncias de objetos/tipos:const ponto origem(ZERO,ZERO);const float ZERO=0.0;

• Const qualificando funções:float distancia(const ponto hi) const ;

• Const qualificando argumentos:float distancia(const ponto hi) const;

1.2.2.1.5.2. Funções inline

O que são funções inline?

Imagine uma chamada de uma função membro void altera_raio(float a)da classe círculo já apresentada, ac.altera_raio(a) . Esta chamadaenvolve a passagem de parâmetros, inserção da função na pilha (stack),retorno de um valor (void ), tudo isso representa uma diminuição davelocidade do programa com relação a um simples: ac.raio=a .

Porque programar desta forma?

Porque é mais seguro, mais próximo dos princípios de orientação aobjetos. Em verdade POO se caracteriza por muitas chamadas demétodos e uso do "heap", área de memória usada pela alocaçãodinâmica.

O que as funções declaradas como inline fazem é traduzir a chamadado método em tempo de compilação em um equivalente ac.raio=17.0 ,evitando todo o contratempo descrito. Essa tradução do método écolocada na seqüência de código do programa, pode-se ter váriostrechos que chamariam funções, desviariam o fluxo do programa até oretorno desta, convertidos em instruções simples.

Como desvantagem temos o aumento do tamanho do programa, vistoque passarão a existir várias cópias diferentes da função no programa(uma para cada argumento) ao invés de um só protótipo de função queera colocado na pilha no momento da chamada e então tinha osargumentos substituídos.

63

Nos programa anteriores sobre a classe círculo, se a função membromostra fosse inline haveria uma conversão da chamada interna (dentrode mostra) de retorna_raio() em simplesmente ac.raio . Pode haverconversão de várias funções inline aninhadas, estas conversões sãoseguras, porque são feitas pelo compilador.

Normalmente é vantajoso usar inline para funções pequenas que nãoaumentem muito o tamanho do programa ou funções onde velocidade écrucial. Aqui vale a conhecida regra 80:20, oitenta porcento do tempo doprograma é gasto em vinte por cento dos métodos. Porém oprogramador não precisa se preocupar muito com funções inline nafase de desenvolvimento, este é um recurso C++ para aumento deeficiência que pode muito bem ser deixado para o final do projeto. Saibaporém que as diferenças de tempo decorrentes de seu uso sãosensíveis.

Este exemplo explora as possibilidades que temos para declararfunções membro e como declará-las para que sejam do tipo inline:

#include <iostream.h>struct ponto{float x;float y;void inicializa(float a,float b){ x=a; y=b; } //Apesar de nao especificado compilador//tenta expandir chamada da funcao como inline porque//esta dentro da definicao da classe.void mostra(void); //com certeza nao e' inline,//externa a classe e sem qualificador.inline void move(float dx,float dy); //e' inline ,//prototipo, definicao};void ponto::mostra(void){cout << "X:" << x << " , Y:" << y << endl;}inline void ponto::move(float dx,float dy)//implementacao, codigo{x+=dx;y+=dy;}void main(){

64

ponto ap;ap.inicializa(0.0,0.0);ap.mostra();ap.move(1.0,1.0);ap.mostra();ap.x=100.0;ap.mostra();}

Comentários

O compilador tenta converter a função inicializa em inline , embora nãoesteja especificado com a palavra reservada inline que isto é para serfeito. Esta é uma regra, sempre que a função estiver definida na própriaclasse (struct{} ) o compilador tentará convertê-la em inline .

Foi dito que o compilador tenta porque isto pode variar de compiladorpara compilador, se ele não consegue converter em inline , devido àcomplexidade da função, você é normalmente avisado, tendo que trocaro lugar da definição da função membro.

Note que se a função membro é implementada fora da classe, tanto oprotótipo da função membro, quanto a implementação devem virespecificados com inline para que a conversão ocorra.

Resultado do programa

X:0 , Y:0X:1 , Y:1X:100 , Y:1

1.2.2.1.5.3. Alocação Dinâmica com new e delete

Ponteiros, ("pointers")

Este exemplo mostra como trabalhar com ponteiros para variáveis detipos pré-definidos (não definidos pelo usuário) usando new e delete .

O programa a seguir cria um ponteiro para uma variável inteira, alocamemória para esta variável e imprime seu valor.

65

#include <iostream.h>void main(){int* a;//declara um ponteiro para endereco de variavel//inteiraa=new int(3);//aloca memoria para o apontado por a, gravando neste//o valor 3cout << (*a) << endl ;//imprime o valor do apontado por adelete a;//desaloca memoria}

Resultado do programa

3

Comentários

Se a fosse uma struct ou class e tivesse um dado membro chamadodd , poderíamos obter o valor de dd através de (*a).dd que pode sertodo abreviado em a->dd onde -> é uma seta, ou flecha que pode-se lercomo "o apontado " novamente. Os parênteses em (*a).dd sãonecessários devido a precedência do operador . com relação ao *.

Observação

int* a;a=new int(3);

pode ser abreviado por:

int* a=new int(3);

Vetores Criados Estaticamente

O exemplo a seguir aloca estaticamente, em tempo de compilação, umvetor de inteiros com três posições. Em seguida, gravamos as trêsposições e as mostramos na tela:

66

#include <iostream.h>void main(){int a[3];//aloca o vetor de tamanho 3, estaticamentea[0]=1;//atribui a posicao indice 0 do vetora[1]=2;//atribui 2 a posicao indice 1 do vetora[2]=3;//atribui 3 a posicao indice 2 do vetorcout << a[0] << " " << a[1] << " " << a[2] << endl;//mostra o vetor}

Resultado do programa

1 2 3

Resumo da sintaxe de vetores

int a[3]; //cria um vetor de inteiros a com tres//posicoes, indices uteis de 0 ate 2float b[9]; //cria um vetor de float b com nove//posicoes, indices uteis de 0 ate 8b[8]=3.14156295; //grava 3.1415... na ultima posicao//do vetor bif (b[5]==2.17) { /*acao*/} ; //teste de igualdade

Diagrama do vetor

Perceba que a faixa útil do vetor vai de 0 até (n-1) onde n é o valor dadocomo tamanho do vetor no momento de sua criação, no nosso caso 3.

Nada impede que se grave ou leia índices fora dessa área útil, isso émuito perigoso, porque fora dessa área, o que se tem são outrasvariáveis de memória e não o espaço reservado para seu vetor. Éperfeitamente aceitável, embora desastroso, escrever em nossoprograma a[4]=3; . O compilador calcula o endereço de memória daposição 4 com base na posição inicial do vetor e o tamanho do tipoalocado. Após calculado o endereço da posição 4 o valor 3 é copiado,apagando o conteúdo anterior!

67

Comentários

Note que não estamos usando ponteiros neste exemplo e é por isso queo vetor é alocado estaticamente, em tempo de compilação, é tambémpor esse motivo que o argumento que vai no lugar do 3 no código inta[3]; deve ser uma expressão constante e não uma variável.

Cópia de Objetos com Vetores Alocados Estaticamente

No primeiro exemplo do TAD fração vimos que o compilador fornececópia bit a bit para objetos. O exemplo seguinte mostra um caso ondeesta cópia oferecida pelo compilador é segura.

#include <iostream.h>class vetor_tres{public:int vet[3];//vetor alocado estaticamente numa classe.vetor_tres(int a,int b,int c){ vet[0]=a; vet[1]=b; vet[2]=c; }//construtor do vetorvoid mostra(void){ cout << vet[0] << " " << vet[1] << " " << vet[2] <<endl;}//funcao membro para mostrar o conteudo do vetor};void main(){vetor_tres v1(1,2,3);//criacao de um objeto vetor.vetor_tres v2(15,16,17);//criacao de um objeto vetor.v1.mostra();//mostrando o conteudo de v1.v2.mostra();//mostrando o conteudo de v2.v2=v1;//atribuindo objeto v1 ao objeto v2.v2.mostra();//mostrando v2 alterado.v1.vet[0]=44;v1.mostra();

68

//mostrando o conteudo de v1.v2.mostra();//mostrando o conteudo de v2.}

Resultado do programa

1 2 315 16 171 2 344 2 31 2 3

Comentários

No caso de alocação estática, quando o tamanho do vetor é conhecidoem tempo de compilação, a cópia é segura. Por cópia segura entenda:as posições do vetor são copiadas uma a uma e os objetos não ficamfazendo referência a um mesmo vetor. Isso pode ser visto no resultadodo programa, quando alteramos a cópia de v1, v1 não se altera.

Vetores Criados Dinamicamente

No exemplo a seguir, os vetores são alocados dinamicamente, ou seja,o programador determina em tempo de execução qual o tamanho dovetor.

#include <iostream.h>void main(){int tamanho;//armazena o tamanho do vetor a criar.int* vet;//ponteiro para inteiro ou vetor de inteiro ainda nao//criadocout << "Entre com o tamanho do vetor a criar";cin >> tamanho;vet=new int[tamanho];//alocando vetor de "tamanho" posicoes comecando em//a[0]for (int i=0;i<tamanho;i++){

69

cout << "Entre com o valor da posicao " << i << ":";cin >> vet[i];cout << endl;}//loop de leitura no vetorfor (int j=0;j<tamanho;j++){cout << "Posicao " << j << ":" << vet[j]<<endl;}//loop de impressao do vetor}

Resultado do programa

Entre com o tamanho do vetor a criar3Entre com o valor da posicao 0:1Entre com o valor da posicao 1:2Entre com o valor da posicao 2:3Posicao 0:1Posicao 1:2Posicao 2:3

Comentários

• int* a; declara um ponteiro para inteiro.• a=new int[10]; diferente de new int(10); os colchetes indicam que é

para ser criado um vetor de tamanho 10 e não uma variável de valor10. Ao contrário da alocação estática, o parâmetro que vai no lugardo valor 10 não precisa ser uma expressão constante.

• int* a; a=new int[10]; equivale à abreviação int* a=new int[10];• A faixa de índices úteis do vetor novamente vai de 0 até (10-1) ou

(n-1).

Cópia de Objetos com Vetores Alocados Dinamicamente

Essa determinação do tamanho do vetor em tempo de execução vaitornar a cópia de objetos feita pelo compilador diferente, ele vai copiar oponteiro para o vetor, ou seja os objetos passam a compartilhar aestrutura na memória, o que nem sempre pode ser desejável!

70

#include <iostream.h>class vetor_tres{public:int* vet;//vetor alocado estaticamente numa classe.vetor_tres(int a,int b,int c){vet=new int[3];vet[0]=a;vet[1]=b;vet[2]=c;}//construtor do vetorvoid mostra(void){ cout << vet[0] << " " << vet[1] << " " << vet[2] <<endl;}//funcao membro para mostrar o conteudo do vetor};void main(){vetor_tres v1(1,2,3);//criacao de um objeto vetor.vetor_tres v2(15,16,17);//criacao de um objeto vetor.v1.mostra();//mostrando o conteudo de v1.v2.mostra();//mostrando o conteudo de v2.v2=v1;//atribuindo objeto v1 ao objeto v2.v2.mostra();//mostrando v2 alterado.v1.vet[0]=44;v1.mostra();//mostrando o conteudo de v1.v2.mostra();//mostrando o conteudo de v2.}

Resultado do programa

1 2 315 16 17

71

1 2 344 2 344 2 3

Comentários

Quando alteramos a cópia de v1, v1 se altera. Isso ocorre porque ovetor não é copiado casa a casa, só se copia o ponteiro para a posiçãoinicial do vetor, a partir do qual se calcula os endereços das posiçõesseguintes v[3]==*(v+3) .

#include <iostream.h>void main(){int* v;v=new int[3];cout << *(v+1)<<endl;//imprime o lixo contido na memoria de v[1]cout << v[1] <<endl;//imprime o lixo contido na memoria de v[1]//*(v)==v[0] é uma expressao sempre verdadeira}

Resultado do programa

152152

Comentários

O que é importante deste exemplo é que só se armazena a posiçãoinicial do vetor, as outras posições são calculadas com base no tamanhodo tipo alocado e regras de aritmética de ponteiros. Vetores alocadosdinamicamente e ponteiros são a mesma coisa.

Tad e Alocação Dinâmica

Um dos grandes problemas de trabalhar com vetores comuns de C++(int * a; a=new int[10]; a[22]=3; ) é que freqüentemente lemos índicesinválidos, ou pior gravamos acima deles.

Gravar acima de um índice fora dos limites de um vetor é um errofreqüente em programação C++. Saiba que fazendo isso você pode

72

estar apagando instruções de outros programas na memória e outrasinformações importantes!

Não checar os índices de um vetor em programas grandes é comoinstalar uma bomba relógio em seu código, é muito provável que emalgum instante você ou até mesmo outra pessoa usando seu programase distraia e acabe por escrever uma rotina que acessa um índiceinválido de um vetor, fazendo na maioria das vezes o programa falhar.

A proposta deste exemplo é criar um tipo abstrato de dados vetor comuma interface flexível que sirva para várias aplicações e possa serfacilmente estendida.

//file exvet1.h//header file para classe vetorconst int inicio=0;class vetor{private:int* v;//este e' o vetorint tamanho;//tamanho maximo do vetor,public:vetor (int tam);//construtor, aloca memória para o vetor.void atribui(int index,int valor);//altera uma posicao do vetorint conteudo(int index);//retorna conteudo de posicao do vetorint maximo(void);//retorna o maior elemento do vetorint primeiro(void);//primeiro indice do vetorint ultimo(void);//ultimo indice do vetor~vetor() {delete v;}//inline function ou use delete v[];};

//codigo, implementacao, para o header file#include <iostream.h>#include <stdlib.h>

73

#include "exvet1.h"vetor::vetor (int tam){v=new int[tam]; tamanho=tam;}void vetor::atribui(int index,int valor){if (index<tamanho && index>=inicio)v[index]=valor;}int vetor::conteudo(int index){if (index>=tamanho || index<inicio) {cerr << "Forados limites"; exit(1);}return v[index];}int vetor::primeiro(void){ return inicio;}int vetor::ultimo(void){ return tamanho-1;}int vetor:: maximo(void){int candidato=inicio; //candidato ao maximofor (int i=inicio;i<tamanho;i++)if (v[i]>v[candidato]) candidato=i;return v[candidato];}

//programa pricipal#include <iostream.h>#include "exvet1.h"main(){int aux;//para ler valor a atribuirvetor meu(5);for (int i=meu.primeiro();i<=meu.ultimo();i++){cout << "Entre com valor da posicao:" << i << "\n";cin >> aux;meu.atribui(i,aux);}for (int j=meu.primeiro();j<=meu.ultimo();j++) cout<<meu.conteudo(j)<< " ";cout <<endl << "Maximo:" << meu.maximo();return 0;}

74

Comentários

O método ~vetor() {delete v;} //use delete []v; depende do compilador.É um destrutor. A única ação do destrutor é liberar a memória ocupadapelo atributo vetor de inteiros (int * v ) da classe vetor.

Note quando não dispúnhamos do destrutor o programador era obrigadoa apagar passo a passo todas as estruturas dinâmicas dos objetos quesaíam de escopo.

Resultado do programa

Entre com valor da posicao:04Entre com valor da posicao:15Entre com valor da posicao:29Entre com valor da posicao:32Entre com valor da posicao:414 5 9 2 1Maximo:9

1.2.2.1.5.4. Referência &

O operador &, também chamado de operador "endereço de... " é usadopara fazer passagem de parâmetros por referência. Este operadorfornece o endereço, a posição na memória de uma variável, de umargumento etc. Sua utilização é muito simples, se a é uma variávelinteira, &a retorna um ponteiro para a. O programa a seguir ilustra asintaxe do operador:

#include <iostream.h>void main(){int a;a=10;int* p;p=& a;(*p)=13;cout << a; }

75

O programa a seguir usa o operador "endereço de " para modificarargumentos, parâmetros de uma função, ou seja utiliza passagem porreferência, equivalente ao VAR de Pascal.

#include <iostream.h>void incrementa(int& a){a++;}//primeira funcao que usa passagem por referenciavoid troca(int& a,int& b){int aux=a;a=b;b=aux;}//segunda funcao que usa passagem por referenciavoid main(){int i1=10;int i2=20;incrementa(i1);cout << i1 << endl;troca(i1,i2);cout << i1 << endl;}

Resultado do programa

1120

Comentários

As funções criadas no programa são capazes de alterar seusparâmetros. A função incrementa , incrementa seu único parâmetro e afunção troca , troca os dois parâmetros inteiros.

76

1.2.2.2. Herança

1.2.2.2.1. Hierarquias de Tipos

Neste tópico, será mostrado como construir hierarquias de tipo porgeneralização/especialização.

1.2.2.2.1.1. Uma Hierarquia Simples

Herança Pública

Na herança pública as classes filhas passam a ter as mesmas funçõesmembro public da classe pai, as classes filhas podem acrescentarfunções membro, dados membro e até redefinir funções membroherdadas.

Os atributos da classe pai não são acessíveis diretamente na classefilha a não ser que sejam qualificados como protected . Por isso é quese diz que as classes filhas garantem pelo menos o comportamento"behaviour " da classe pai, podendo acrescentar mais características.

Construtores e herança

No construtor de uma classe filha o programador pode incluir a chamadado construtor da classe pai.

Destrutores e herança

Quando um objeto da classe derivada é destruído, o destrutor da classepai também é chamado dando a oportunidade de liberar a memóriaocupada pelos atributos private da classe pai.

//header fileclass ponto{private:float x; //sao ocultos por defaultfloat y; //sao ocultos por defaultpublic: //daqui em diante tudo e acessivel.ponto(float a,float b);void inicializa(float a,float b);

77

float retorna_x(void);float retorna_y(void);void altera_x(float a);void altera_y(float b);void mostra(void);};class ponto_reflete:public ponto //classe filha{private: //se voce quer adicionar atributos...public:ponto_reflete(float a, float b);void reflete(void);};class ponto_move:public ponto{public:ponto_move(float a,float b);void move(float dx,float dy);};

//implementation file#include <iostream.h>#include "pontos.h"ponto::ponto(float a,float b){inicializa(a,b);}void ponto::inicializa(float a,float b){x=a;y=b;}float ponto::retorna_x(void){ return x; }float ponto::retorna_y(void){ return y; }void ponto::altera_x(float a){ x=a; }void ponto::altera_y(float b){ y=b; }void ponto::mostra(void){cout << "(" << x << "," << y << ")" <<endl;

78

}ponto_reflete::ponto_reflete(float a,floatb):ponto(a,b){ }void ponto_reflete::reflete(void){altera_x(-retorna_x());altera_y(-retorna_y());}ponto_move::ponto_move(float a,float b):ponto(a,b){ }void ponto_move::move(float dx,float dy){altera_x(retorna_x()+dx);altera_y(retorna_y()+dy);}

#include <iostream.h>#include "pontos.h"void main(){ponto_reflete p1(3.14,2.17);p1.reflete();cout << "P1";p1.mostra();ponto_move p2(1.0,1.0);p2.move(.5,.5);cout << "P2";p2.mostra();}

Resultado do programa

P1(-3.14,-2.17)P2(1.5,1.5)

Herança "Private"

Pode-se especificar uma classe herdeira por herança private como:class herdeira: private nome_classe_base; . As funções membrodessa classe base só são acessíveis dentro das declarações da classefilha, ou seja, a classe filha não atende por essas funções membro, mas

79

pode usá-las em seu código.

Herança private é um recurso que se precisa tomar cuidado quandousar. Normalmente, quando usamos herança dizemos que a classe filhagarante no mínimo o comportamento da classe pai (em termos defunções membro) , a herança private pode invalidar esta premissa.

Muitos programadores usam herança private quando ficaria maiselegante, acadêmico, trabalhar com agregação. Uma classe pilha podeser construída a partir de uma classe que implementa uma lista ligadapor agregação ou por herança private . Na agregação (a escolhida emhierarquias de implementação ) a classe pilha possui um dadomembro que é uma lista ligada.

1.2.2.2.1.2. Protected

O exemplo a seguir é Igual ao exemplo anterior, mas agora tornando osatributos da classe pai acessíveis para as classes filhas através do usode protected . Protected deixa os atributos da classe pai visíveis,acessíveis "hierarquia abaixo ".

//header fileclass ponto{protected://*****aqui esta a diferenca ******float x;//visiveis hierarquia abaixofloat y;//visiveis hierarquia abaixopublic://daqui em diante tudo e acessivel.ponto(float a,float b);void inicializa(float a,float b);float retorna_x(void);float retorna_y(void);void altera_x(float a);void altera_y(float b);void mostra(void);};class ponto_reflete:public ponto{

80

private://se voce quer adicionar dados membro encapsulados...public:ponto_reflete(float a, float b);void reflete(void);};class ponto_move:public ponto{public:ponto_move(float a,float b);void move(float dx,float dy);};

//implementation file#include <iostream.h>#include "pontos.h"ponto::ponto(float a,float b){inicializa(a,b);}void ponto::inicializa(float a,float b){x=a;y=b;}float ponto::retorna_x(void){ return x; }float ponto::retorna_y(void){ return y; }void ponto::altera_x(float a){ x=a; }void ponto::altera_y(float b){ y=b; }void ponto::mostra(void){cout << "(" << x << "," << y << ")" <<endl;}ponto_reflete::ponto_reflete(float a,floatb):ponto(a,b){ }void ponto_reflete::reflete(void){x=-x;

81

//*** protected da esse tipo de acesso aos atributosda classe paiy=-y;}ponto_move::ponto_move(float a,float b):ponto(a,b){ }void ponto_move::move(float dx,float dy){x=x+dx;//acesso so na hierarquia, no resto do programa nao.y=y+dy;}

#include <iostream.h>#include "pontos.h"void main(){ponto_reflete p1(3.14,2.17);p1.reflete();cout << "P1";p1.mostra();ponto_move p2(1.0,1.0);p2.move(.5,.5);cout << "P2";p2.mostra();}

1.2.2.2.1.3. Redefinição de Funções Membro Herdadas

Neste exemplo será redefinido a função membro mostra para a classefilha ponto_reflete .

Comentários

Uma classe filha pode fornecer uma outra implementação para umafunção membro herdada, caracterizando uma redefinição "overriding "de função membro. Importante: a função membro deve ter a mesmaassinatura (nome, argumentos e valor de retorno), senão não se trata deuma redefinição e sim sobrecarga "overloading ".

No nosso exemplo, a classe ponto_reflete redefine a função membromostra da classe pai, enquanto que a classe herdeira ponto_move

82

aceita a definição da função membro mostra dada pela classe pontoque é sua classe pai.

//header fileclass ponto{private:float x;//sao ocultos por defaultfloat y;//sao ocultos por defaultpublic://daqui em diante tudo e acessivel.ponto(float a,float b);void inicializa(float a,float b);float retorna_x(void);float retorna_y(void);void altera_x(float a);void altera_y(float b);void mostra(void);};class ponto_reflete:public ponto{private://se voce quer adicionar dados membropublic:ponto_reflete(float a, float b);void reflete(void);void mostra(void);//redefinicao};class ponto_move:public ponto{public:ponto_move(float a,float b);void move(float dx,float dy);//esta classe filha nao redefine mostra};

//implementation file#include <iostream.h>#include "pontos.h"ponto::ponto(float a,float b)

83

{inicializa(a,b);}void ponto::inicializa(float a,float b){x=a;y=b;}float ponto::retorna_x(void){ return x; }float ponto::retorna_y(void){ return y; }void ponto::altera_x(float a){ x=a; }void ponto::altera_y(float b){ y=b; }void ponto::mostra(void){cout << "(" << x << "," << y << ")" <<endl;}ponto_reflete::ponto_reflete(float a,floatb):ponto(a,b){ }void ponto_reflete::reflete(void){altera_x(-retorna_x());altera_y(-retorna_y());}void ponto_reflete::mostra(void){cout << "X:" << retorna_x() << " Y:";cout << retorna_y() << endl;}//somente altera o formato de impressaoponto_move::ponto_move(float a,float b):ponto(a,b){ }void ponto_move::move(float dx,float dy){altera_x(retorna_x()+dx);altera_y(retorna_y()+dy);}

#include <iostream.h>

84

#include "pontos.h"void main(){ponto_reflete p1(3.14,2.17);p1.reflete();cout << "P1";p1.mostra();ponto_move p2(1.0,1.0);p2.move(.5,.5);cout << "P2";p2.mostra();}

Resultado do programa

P1X:-3.14 Y:-2.17P2(1.5,1.5)

1.2.2.2.1.4. Uma Hierarquia de Listas Ligadas

Agora um dos objetivos do próximo é obter uma implementação de listaque possa ser reutilizada para criação de pilhas e filas.

A associação entre as classes lista e nó é uma associação do tipo "hasmany " enquanto que a associação entre a classe lista e as classeslistaultimo e listaordenada indica herança, é uma associação do tipo"is a ".

#ifndef MLISTH_H#define MLISTH_H

85

#include <stdlib.h>#include <iostream.h>//Criacao de uma hierarquia de listas ligadas.//O elemento da lista e' um inteiroenum Boolean{FALSE,TRUE};class no{ //este e' o no da lista ligada, so e' usado//por elaprivate:int info; //informacaono* prox; //ponteiro para o proximopublic:no();no(int i,no* p);no* get_prox(void);void set_prox(no* p);int get_info(void);void set_info(int i);no* dobra(void);~no(void);} ;class lista{ //esta e' a lista ligada comum.protected: //"visivel hierarquia abaixo"no* primeiro; //primeiro no da lista, aqui eu insiro//e removo.public:lista(void);Boolean vazia(void)const;Boolean contem(int el)const;void insere_primeiro(int elem);int* remove_primeiro();void mostra()const;~lista(void);}; //fim classe listaclass listaultimo:public lista { //essa e a listautil para//implementar pilhas e filas.protected: //protected e uma opcao outra e'get_ultimo() e set_...no* ultimo;public:listaultimo(void);void insere_ultimo(int elem); //novavoid insere_primeiro(int elem); //redefinicaoint* remove_primeiro();//redefinicao

86

~listaultimo(void);//as operacoes nao redefinidas sao validas.};class listaordenada:public lista {//essa e' a lista comum comaprimoramentos/especializacoespublic:listaordenada(void);Boolean contem(int el)const;void insere_primeiro(int elem);//insere em ordemint* remove_elemento(int el);//remove elemento el se existir~listaordenada(void);};#endif

#include "mlisth.h"#include <iostream.h>#include <stdlib.h>no::no(){prox=NULL;cout << "Hi";}no::no(int i,no* p){info=i;prox=p;cout << "Hi";}no* no::get_prox(void){return prox;}void no::set_prox(no* p) {prox=p;}int no::get_info(void) {return info;}void no::set_info(int i) {info=i;}no* no::dobra(void){if (get_prox()==NULL) return new no(get_info(),NULL);else return new no(get_info(),this->get_prox()->dobra());//recursividade para duplicacao da lista}no::~no(void) {cout << "bye";}lista::lista(void):primeiro(NULL) {}//bloco de codigo vazioBoolean lista::vazia(void)const{return Boolean(primeiro==NULL);}

87

Boolean lista::contem(int el) const//mais rapido que//iterador{no* curr;int Conti;curr=primeiro;Conti=TRUE;while ((curr!=NULL) && Conti ){if (curr->get_info()!=el){if (curr->get_prox()==NULL) Conti=FALSE; elsecurr=curr->get_prox();}elseConti=FALSE;}; //whilereturn Boolean(curr->get_info()==el);};void lista::insere_primeiro(int elem){no* insirame;if (primeiro==NULL) //lista vaziaprimeiro=new no(elem,NULL);else {insirame=new no(elem,primeiro);primeiro=insirame;};};int* lista::remove_primeiro(){int* devolvame=new int; //returnno* temp; //to deleteif (primeiro==NULL) return NULL; //lista vaziaelse {(*devolvame)=primeiro->get_info();temp=primeiro;primeiro=primeiro->get_prox();delete temp;return devolvame;};};void lista::mostra() const{no* curr;cout << "=";

88

curr=primeiro;while (curr!=NULL){cout <<"("<<curr->get_info()<<")"<<"-";curr=curr->get_prox();};}lista::~lista(void){no* temp;while (primeiro!=NULL){temp=primeiro;primeiro=primeiro->get_prox();delete temp;};}listaordenada::listaordenada(void):lista(){};Boolean listaordenada::contem(int el)const{no* curr;Boolean conti=TRUE;curr=primeiro;while ((curr!=NULL) && conti){if (curr->get_info()<el)curr=curr->get_prox();else conti=FALSE;};if (curr==NULL) return FALSE;else return Boolean(curr->get_info()==el);}void listaordenada::insere_primeiro(int elem){no* curr=primeiro;no* prev=NULL;no* insirame;Boolean conti=TRUE;while ((curr!=NULL) && conti){if (curr->get_info()<elem){prev=curr; curr=curr->get_prox();}else conti=FALSE;

89

};insirame=new no(elem,curr);if (prev==NULL) primeiro=insirame;else prev->set_prox(insirame);}int* listaordenada::remove_elemento(int el){int* devolvame=new int;no* curr=primeiro;no* prev=NULL;no* deleteme;Boolean conti=TRUE;while ((curr!=NULL) && conti) //acha lugar onde podeestar el{if (curr->get_info()<el){prev=curr; curr=curr->get_prox();} //andaelse conti=FALSE;};if (curr==NULL) return NULL; //fim de lista ou vaziaelse //pode ser o elemento ou ele nao existe{if (curr->get_info()==el){deleteme=curr;if (prev==NULL) //lista so com um elemento ouprimeiro elprimeiro=curr->get_prox();else{prev->set_prox(curr->get_prox());}(*devolvame)=deleteme->get_info(); //so paraverificardelete deleteme;return devolvame;}else return NULL;}}listaordenada::~listaordenada(void){cout << "Lista destruida.";};listaultimo::listaultimo(void):lista(){

90

ultimo=NULL;}void listaultimo::insere_ultimo(int elem){no* insirame;insirame=new no(elem,NULL);if (ultimo==NULL) ultimo=insirame; //lista vaziaelse {ultimo->set_prox(insirame);ultimo=insirame;};if (primeiro==NULL) primeiro=ultimo; //lista vazia}void listaultimo::insere_primeiro(int elem)//redefinicao{no* insirame;if (primeiro==NULL) //lista vazia{primeiro=new no(elem,ultimo);ultimo=primeiro;}//lista vaziaelse {insirame=new no(elem,primeiro);primeiro=insirame;};}int* listaultimo::remove_primeiro()//redefinicao{int* devolvame=new int; //returnno* temp; //to deleteif (primeiro==NULL) return NULL; //lista vaziaelse {(*devolvame)=primeiro->get_info();temp=primeiro;primeiro=primeiro->get_prox();delete temp;if (primeiro==NULL) ultimo=NULL; //volta lista vaziareturn devolvame;};}listaultimo::~listaultimo(void){no* temp;

91

while (primeiro!=NULL){temp=primeiro;primeiro=primeiro->get_prox();delete temp;};delete ultimo;}

#include "mlisth.h"main(){listaordenada minha;char option; //use in menu as option variableint el; //elemento a inserirint* receptor;do {cout <<"\n"; //menu options displaycout <<"P:Insere no primeiro.\n";cout <<"R:Remove no primeiro.\n";cout <<"D:Remove elemento.\n";cout <<"E:Existe elemento?\n";cout <<"V:Vazia?\n";cout <<"M:Mostra lista.\n";cout <<"Q:Quit teste lista.\n";cout <<"Entre comando:";cin >> option; //reads user optionswitch(option) //executes user option{case 'D':case 'd':cout << "Entre elemento:";cin >>el;receptor=minha.remove_elemento(el);if (receptor==NULL) cout << "NULL" << endl;else cout << (*receptor) << endl;break;case 'P':case 'p':cout << "Entre elemento:";cin >> el;minha.insere_primeiro(el);break;

92

case 'R':case 'r':if (!minha.vazia())cout << (*minha.remove_primeiro()) <<endl;else cout << "NULL, Lista vazia." <<endl;break;case 'M':case 'm':minha.mostra();break;case 'E':case 'e':cout << "Entre elemento:";cin >>el;cout << minha.contem(el);break;case 'V':case 'v':cout << minha.vazia();break;default: ;} //switch-case code block} while ((option!='Q') && (option!='q')); //menu loopcode blockreturn 0;} //main code block

Comentários

Note que o programa principal só testa a listaordenada .

1.2.2.2.2. Hierarquias de Implementação

Nossas hierarquias de implementação em termos de código (herança)não são hierarquias, usamos delegação para obter pilhas a partir delistas. Agregamos uma lista em nossas classes e usamos esta lista deacordo com a lógica envolvida.

1.2.2.2.2.1. Fila a Partir de Uma Lista

Reuso de código de uma lista ligada para a implementação de uma filaatravés de agregação. Para podermos declarar e usar um objeto lista na

93

nossa classe fila precisamos conhecer sua interface. Sabemos quenosso objeto lista permite inserir em ambas extremidades, início e fimda lista, mas só permite remoções em um extremo, o início.

Como uma fila permite inserções somente num extremo e remoções nosextremo oposto, precisaremos usar nossa lista da seguinte forma:inserção no final da lista e remoções no começo.

//header file para a classe fila#include "mlisth.h"class fila { //agregacao de uma listaprivate:listaultimo al; //a listapublic:fila();Boolean vazia();Boolean contem(int el);void insere(int el);int* remove();void mostra();};

//implementacao para a classe fila#include "mqueue.h"#include "mlisth.h"fila::fila(){};Boolean fila::vazia(){return al.vazia();}Boolean fila::contem(int el){return al.contem(el);}void fila::insere(int el){al.insere_ultimo(el);}int* fila::remove(){return al.remove_primeiro();}void fila::mostra(){al.mostra();}

//programa principal, testes da classe fila#include "mqueue.h"main(){fila minha;

94

char option; //usada em menu como variavel de opcaoint el; //elemento a inserirdo {cout <<"\n"; //opcoes do menucout <<"I:Insere.\n";cout <<"R:Remove.\n";cout <<"M:Mostra fila.\n";cout <<"Q:Quit fila test.\n";cout <<"V:Vazia?\n";cout <<"C:Contem?\n";cout <<"Entre comando:";cin >> option; //le opcao do usuarioswitch(option) //executa opcao do usuario{case 'I':case 'i':cout << "Entre elemento:";cin >>el;minha.insere(el);break;case 'R':case 'r':if (!minha.vazia())cout << (*minha.remove()) <<endl;else cout << "NULL, fila vazia." <<endl;break;case 'C':case 'c':cout << "Entre elemento:";cin >>el;cout << minha.contem(el);break;case 'M':case 'm':minha.mostra();break;case 'V':case 'v':cout << "Resultado:" << minha.vazia() <<endl;break;default: ;} //switch-case bloco de codigo} while ((option!='Q') && (option!='q')); //loop do//menu fim

95

return 0;} // bloco de codigo principal

1.2.2.3. Polimorfismo, Funções Virtuais

Existem vários tipos de polimorfismo.

1.2.2.3.1. O Que Significa Polimorfismo

Polimorfismo, do grego: muitas formas. Polimorfismo é a capacidade deum operador executar a ação apropriada dependendo do tipo dooperando. Aqui operando e operador estão definidos num sentido maisgeral: operando pode significar argumentos atuais de um procedimentoe operador o procedimento, operando pode significar um objeto eoperador um método, operando pode significar um tipo e operador umobjeto deste tipo.

1.2.2.3.1.1. Copy Constructor

A função membro ponto (ponto& a); é um copy constructor , alémdisso tem o mesmo nome que ponto (float dx, float dy); . Talduplicação de nomes pode parecer estranha, porém C++ permite queeles coexistam para uma classe porque não tem a mesma assinatura(nome + argumentos). Isto se chama sobrecarga de função membro, ocompilador sabe distinguir entre esses dois construtores.

Outras funções membro, não só construtores poderão ser redefinidas,ou sobrecarregadas para vários argumentos diferentes.

O que é interessante para nós é o fato de o argumento do construtorponto(ponto& a); ser da mesma classe para qual o construtor foiimplementado, esse é o chamado "copy constructor ". Ele usa umobjeto de seu tipo para se inicializar. Outros métodos semelhantesseriam: circulo (circulo& a); mouse (mouse& d); .

#include <iostream.h>struct ponto{float x;float y;

96

ponto(float a,float b);//construtor tambem pode ser inline ou naoponto(ponto& a); //copy constructorvoid mostra(void);void move(float dx,float dy);};ponto::ponto(float a,float b){x=a;y=b;}ponto::ponto(ponto& a){x=a.x;y=a.y;}void ponto::mostra(void){cout << "X:" << x << " , Y:" << y << endl;}void ponto::move(float dx,float dy){x+=dx;y+=dy;}void main(){ponto ap(0.0,0.0);ap.mostra();ap.move(1.0,1.0);ap.mostra();ponto ap2(ap);ap2.mostra();}

Comentários

Observe o código:

ponto::ponto(ponto& a){x=a.x;y=a.y;}

97

Essa função membro, esse método, pertence a outro objeto que não oargumento a, então para distinguir o atributo x deste objeto, do atributo xde a usamos a.x e simplesmente x para o objeto local (dono da funçãomembro).

1.2.2.3.1.2. Sobrecarga de Função em C++

Sobrecarga "Overloading " de função é um tipo de polimorfismo. C++permite que funções de mesmo nome tenham parâmetros distintos. Esteexemplo mostra a sobrecarga da função abs que calcula o valorabsoluto de um número:

//header file funcover.hfloat abs(float a);int abs(int a);

//implementation file#include "funcover.h"float abs(float a){if (a>0.0) return a;else return -a;}int abs(int a){if (a>0) return a;else return -a;}

#include <iostream.h>#include "funcover.h"void main(){int i1;float f1;cout << abs(int(-10))<<endl;cout << abs(float(-10.1))<<endl;f1=-9.1;i1=8.0;cout << abs(f1) << endl;

98

cout << abs(i1) << endl;}

Resultado do programa

1010.19.18

Comentários

cout << abs(float(-10.1))<<endl;Quando chamamos a função abs para um valor (-10.1) e não umavariável (possui um tipo), temos que fazer a conversão explícita para ocompilador, porque este não sabe decidir qual função chamar (parafloat ou int ), mesmo estando presente o ponto indicando a casadecimal.

Observe que -10.1 pode ser double ou float . Enquanto que 10 pode serlong ou int .

//header file funcover.hfloat max(float a,float b);float max(float a,float b,float c);int max(int a,int b);

#include "funcover.h"float max(float a,float b){if (a>b) return a;else return b;}float max(float a,float b,float c){if (a>b) return max(a,c);else return max(b,c);}int max(int a,int b){if (a>b) return a;

99

else return b;}

#include <iostream.h>#include "funcover.h"void main(){cout << max(float(1.2),float(3.4),float(2.1))<<endl;cout << max(float(1.5),float(.65)) << endl;cout << max(int(12),int(120));}

Resultado do programa

3.41.5120

1.2.2.3.1.3. "Default Arguments ", Valores Sugestão

Valores sugestão, argumentos padrão ou "default arguments ", sãonomes para um tipo de polimorfismo fornecido por C++.

Para demonstrar o uso de default values vamos relembrar o nosso tipoabstrato de dados fração. Um de seus construtores tinha a seguinteforma: fracao() {num=0; den=1;} //construtor vazio , default enquantoque o construtor normal da fração tinha a seguinte forma: fracao (long t,long m); .

"Default arguments " nos dá a oportunidade de fundir esses doisconstrutores num só resultando no seguinte: fracao (long t=0, longm=1) {num=t; den=m;} onde 1 e 0 são valores sugestão para osargumentos.

A instanciação fracao a() segundo aquele único construtor cria: (0/1)A instanciação fracao b(1) segundo aquele único construtor cria: (1/1)A instanciação fracao c(1,2) segundo aquele único construtor cria: (1/2)

Regras para a criação de "Default arguments"

100

Não são permitidas declarações do tipo fracao (long t=0, long m); umavez que você inseriu um argumento padrão na lista de argumentos todosa direita deste também deverão ter seus valores sugestão. Então, poresta regra a única alternativa restante para o tipo fração seriafracao (long t, long m=1); .

1.2.2.3.1.4. Sobrecarga de Operador

O tipo abstrato de dados fração (versão completa) possui váriosoperadores sobrecarregados. Algumas sobrecargas deste exemploenvolvem o uso da palavra chave friends .

O próximo exemplo é uma extensão da classe vetor para incluir umiterador.

//header file para classe vetor: vet.h#include <iostream.h>#include <stdlib.h> //exit(1)const int inicio=0; //inicio do vetorclass vetor{private:float* v; //pode ser qualquer tipo que atenda as//operacoes < > =int tamanho;public:vetor (int tamanho) ;float& operator[] (int i);float maximo(); //acha o valor maximo do vetorint primeiro(void);int ultimo(void);};vetor::vetor (int tam){v=new float[tam]; tamanho=tam;}int vetor::primeiro (void){return inicio;}int vetor::ultimo (void){return tamanho-1;}float& vetor::operator[](int i){if (i<0 || i>=tamanho){cout << "Fora dos limites! Exit program"; exit(1);}return v[i];}

101

float vetor:: maximo(void){int candidato=inicio;for (int i=inicio;i<tamanho;i++)if (v[i]>v[candidato]) candidato=i;return v[candidato];}

Explicação das operações, das função membros do iterador vetor

• Iteradorvetor (vetor & v);Construtor, já cria o iterador de vetor inicializando-o para apontarpara o começo do vetor.

• virtual int comeca();Inicializa o iterador para o começo do vetor.

• virtual int operator!();Verifica se a iteração não chegou no fim do vetor: 1 indica que nãochegou, 0 indica que chegou no fim do vetor.

• virtual int operator ++ ();Faz o iterador mover adiante uma posição.

• virtual float operator() ();Retorna o elemento daquela posição do vetor.

• virtual void operator= (float entra);Atribui a posição atual do vetor.

• int pos();Retorna a posição (índice) do vetor em que o iterador se encontra,não é virtual porque não faz sentido para um iterador de árvore porexemplo.

//it.h , arquivo com definicoes do iterador.class iteradorvetor{private:vetor vetorref;int posicao;public:iteradorvetor(vetor & v);int comeca();

102

int operator!();int operator ++ ();float operator() ();void operator= (float entra);int pos(); //retorna posicao, n~ virtual pq n~ faz//sentido para arvore por ex.};int iteradorvetor::pos(){return posicao;}int iteradorvetor::operator!(){return posicao<=vetorref.ultimo();}iteradorvetor::iteradorvetor(vetor &vet):vetorref(vet){comeca();}int iteradorvetor::comeca(){posicao=vetorref.primeiro();return operator!();}int iteradorvetor::operator ++(){posicao++;return operator!();}void iteradorvetor::operator=(float entra){vetorref[posicao]=entra;}float iteradorvetor::operator() (){float copia;copia=vetorref[posicao];return copia;}

#include <iostream.h>#include "vet.h"

103

#include "it.h"main(){int repete=0;int ind;float item;vetor meu(5);iteradorvetor itmeu(meu);for (itmeu.comeca();!itmeu;++itmeu){cout << "Entre com valor da posicao:" << itmeu.pos()<< "\n";cin >> item;itmeu=item;}for (itmeu.comeca();!itmeu;++itmeu) cout<< itmeu()<<" ";cout << "\nEntre com o indice da posicao aatualizar:\n";cin >> ind;cout << "Entre com o valor a incluir:";cin >> item;meu[ind]=item;for (int k=meu.primeiro();k<=meu.ultimo();k++) cout<<meu[k]<< " ";cout <<endl << "Maximo:" << meu.maximo();return 0;}

Comentários

O significado do operador é você que define, mas é recomendável darao operador um significado próximo ao já definido na linguagem. Porexemplo: o operador + seria ótimo para representar a concatenação dedois objetos do tipo string. A sintaxe de cada operador é fixa: número deoperandos, precedência etc.

104

3. Especificação e Documentação de

Software

3.1 UML (Unified Modeling Language )

3.1.1 Introdução

O desenvolvimento de sistemas de software de grande porte sãosuportados por métodos de análise e projeto que modelam esse sistemade modo a fornecer para toda a equipe envolvida (cliente, analista,programador etc.) uma compreensão única do projeto.

A UML (Unified Modeling Language ) é o sucessor de um conjunto demétodos de análise e projeto orientados a objeto.

A UML é um modelo de linguagem, não um método. Um métodopressupõe um modelo de linguagem e um processo. O modelo delinguagem é a notação que o método usa para descrever o projeto. Oprocesso são os passos que devem ser seguidos para se construir oprojeto.

O modelo de linguagem é uma parte muito importante do método.Corresponde ao ponto principal da comunicação. Se uma pessoa querconversar sobre o projeto, com outra pessoa, é através do modelo delinguagem que elas se entendem. Nessa hora, o processo não éutilizado.

A UML define uma notação e um meta-modelo. A notação são todos oselementos de representação gráfica vistos no modelo (retângulo, setas,o texto etc.), é a sintaxe do modelo de linguagem. A notação dodiagrama de classe define a representação de itens e conceitos taiscomo: classe, associação e multiplicidade. Um meta-modelo é umdiagrama de classe que define de maneira mais rigorosa a notação.

105

Comportamento do Sistema

O comportamento do sistema é capturado através de análise de casosde uso do sistema.

Descrição informal do sistema automatizado de Matrícula numCurso

No início de cada semestre os alunos devem requisitar um catálogo decursos contendo os cursos oferecidos no semestre. Este catálogo deveconter informações a respeito de cada curso tais como: professor,departamento e pré-requisitos. Desse modo, os alunos podem tomarsuas decisões mais apropriadamente.

O novo sistema permitirá que os alunos selecionem quatro cursosoferecidos para o próximo semestre. Além disso, o aluno indicará doiscursos alternativos, caso o aluno não possa ser matriculado na primeiraopção. Cada curso terá o máximo de 10 e o mínimo de 3 alunos.

Um curso com número de alunos inferior a 3 será cancelado. Para cadamatrícula feita por um aluno, o sistema envia informação ao sistema decobrança para que cada aluno possa ser cobrado durante o semestre.

Os Professores devem acessar o sistema "on line ", indicando quaiscursos irão lecionar. Eles também podem acessar o sistema para saberquais alunos estão matriculados em cada curso.

Em cada semestre, há um prazo para alteração de matrícula. Os alunosdevem poder acessar o sistema durante esse período para adicionar oucancelar cursos.

Definição do Diagrama de Casos de Uso

É um diagrama usado para se identificar como o sistema se comportaem várias situações que podem ocorrer durante sua operação. Descreveo sistema, seu ambiente e a relação entre os dois. Os componentesdeste diagrama são os atores e os "Use Case ".

Ator

Representa qualquer entidade que interage com o sistema. Pode seruma pessoa, outro sistema etc. Algumas de suas características sãodescritas abaixo:

106

• Ator não é parte do sistema. Representa os papéis que o usuáriodo sistema pode desempenhar.

• Ator pode interagir ativamente com o sistema.

• Ator pode ser um receptor passivo de informação.

• Ator pode representar um ser humano, uma máquina ou outrosistema.

"Use Case"

Como foi exemplificado acima, é uma seqüência de ações que o sistemaexecuta e produz um resultado de valor para o ator. Algumas de suascaracterísticas são descritas abaixo:

• Um "Use Case" modela o diálogo entre atores e o sistema.

• Um "Use Case " é iniciado por um ator para invocar uma certafuncionalidade do sistema.

• Um "Use Case" é fluxo de eventos completo e consistente.

• O conjunto de todos os "Use Case " representa todos as situaçõespossíveis de utilização do sistema.

Descrição textual resumida do "Use Case" Matrícula nos Cursos

Este "Use Case" é iniciado pelo aluno. Fornece os meios para o alunocriar, anular, modificar e consultar o formulário de matrícula de um dadosemestre.

Descrição do Fluxo principal de eventos associados a esse "UseCase"

Este "Use Case" inicia-se quando o aluno fornece a chave de acesso. Osistema verifica se a chave de acesso do aluno é valida (E1) eapresenta ao aluno a opção de selecionar o semestre atual ou o próximosemestre (E2).

O aluno seleciona o semestre desejado. O sistema pede ao aluno paraselecionar a atividade desejada: Criar , Consultar , Modificar , Imprimir ,Anular ou Sair do Sistema .

107

Se atividade selecionada é:

• Criar , o subfluxo A1 (Criar uma Matrícula Nova) é executado.• Consultar , o subfluxo A2 (Consulta da Matrícula) é executado.• Modificar , o subfluxo A3 (Modificação da Matrícula) é

executado.• Imprimir , o subfluxo A4 (Imprimir a Matrícula) é executado.• Anular , o subfluxo A5 (Anular Matrícula) é executado.• Sair , o "Use Case " é encerrado.

Descrição dos Subfluxos Alternativos associados a esse "UseCase"

Criar uma Matrícula Nova

O sistema apresenta numa tela um formulário de matrícula em branco.O aluno preenche-o com 4 cursos oferecidos, como primeira escolha epreenche 2 cursos oferecidos como segunda escolha (E3).

A seguir, o aluno submete o formulário preenchido ao sistema. Paracada curso de primeira escolha, o sistema irá verificar se os pré-requisitos são satisfeito (E4) e matricula o aluno no curso, se esseestiver sendo oferecido, e se houver vaga (E5).

O sistema imprime o formulário de matrícula (E6) e envia a informaçãopara ser processado pelo sistema de cobrança (E7). O sistema ficadisponível.

Consulta da Matrícua

O sistema recupera (E8) e apresenta numa tela as seguintesinformações para todos os cursos nos quais o aluno está matriculado:nome do curso, número do curso, dias da semana, horário,localização e número de créditos .

Quando o aluno indica que terminou a consulta, o sistema ficadisponível.

Modificação da Matrícula

O sistema verifica se a data limite para mudanças não expirou (E9). Osistema recupera (E8) e apresenta as seguintes informações para todosos cursos nos quais o aluno está matriculado: nome do curso, número

108

do curso, dias da semana, horário, localização e número decréditos .

O sistema oferece um menu com as seguintes opções: anule um cursooferecido, adicione um curso oferecido ou sair do sistema .

Se a atividade selecionada for:

• Anular um curso matriculado , o procedimento de anulação deum curso (A6), é executado.

• Adicionar um curso oferecido , o procedimento de adição decurso (A7) é executado.

• Sair do sistema , o sistema imprime formulário de matrícula(E6), envia a informação para ser processado pelo sistema decobrança e fica disponível.

Imprimir a Matrícula

O sistema imprime a matrícula do aluno (E6) e fica disponível.

Anular Matrícula

O sistema recupera (E8) e apresenta as informações atuais damatrícula. O sistema pede ao usuário para confirmar a anulação damatrícula. Se efetuada, a matrícula é removida do sistema. Se aanulação não for confirmada, a operação é cancelada e o sistema ficadisponível.

Anular um curso escolhido

O aluno entra com o número do curso a ser anulado. O sistema pede aousuário para confirmar a anulação do curso. Se efetuada, o curso éremovido da matrícula do aluno. Se a anulação não for confirmada, aoperação é cancelada e o sistema fica disponível.

Adicionar um curso

O aluno entra com o número do curso a ser adicionado. O sistemaverifica se os pré-requisitos são satisfeitos (E4) e adiciona o aluno aocurso, se o curso estiver sendo oferecido (E5) e o sistema ficadisponível.

109

Descrição dos Subfluxos de Exceção

O aluno fornece chave de acesso inválida

O aluno pode entrar com a chave de acesso novamente ou sair dosistema.

O aluno fornece um semestre inválido

O aluno pode fornecer novamente um semestre ou sair do sistema.

O aluno fornece número de curso inválido (formato)

O aluno pode fornecer outro número ou sair do sistema.

O aluno não satisfaz todos os requisitos necessários

O aluno é informado que não pode se matricular nesse curso e a razãopara tal. Se possível, um curso alternativo é apresentado. O sistemasegue adiante.

O aluno é informado de que a matrícula para curso selecionadoestá encerrada

Se possível, um curso alternativo é apresentado. O sistema segueadiante.

A matrícula não pode ser imprimida

A informação é armazenada e o aluno é informado de que o pedido deimpressão deve ser repetido. O sistema segue a diante.

O sistema armazenará todas as informações necessárias aosistema de cobrança e a fornecerá assim que possível

O fluxo segue adiante.

O sistema não pode recuperar as informações de matrícula

O aluno deve reiniciar o fluxo desde o início.

110

O sistema informa ao aluno que a matrícula não pode ser alterada

O aluno deve reiniciar o fluxo desde o início.

Documentação de um "Use Case"

Como apresentado acima, a documentação de um "Use Case" écomposta de uma Descrição textual resumida e dos Fluxos de eventos(Fluxo principal, Subfluxos Alternativos e Subfluxos de Exceção).

Cenários

Um cenário primário

Rubens fornece sua chave de acesso. O sistema valida a chave e pedepara Rubens escolher o semestre. Ele escolhe o semestre atual e pedepara criar uma matrícula nova.

Rubens escolhe os cursos primários: Inglês, Geologia, História Geral eÁlgebra. Também seleciona dois cursos alternativos: Teoria Musical eIntrodução à Programação Java.

O sistema constata que Rubens tem todos os pré-requisitos necessáriose adiciona-o às listas de cada curso.

O sistema avisa que a matrícula foi realizada. Imprime o formulário dematrícula de Rubens. Envia informação de cobrança referente aosquatro cursos para ser processada no sistema de cobrança.

Cenários secundários

Walker não seleciona os quatro cursos primários.Um dos cursos primários selecionados não possui mais vagas.Um curso primário ou secundário não está sendo oferecido.

Definição Cenário

É uma instância de um "Use Case ". O "Use Case" deve ser descritoatravés de vários cenários. Devem ser construídos tantos cenáriosquantos forem necessários para se entender completamente todo osistema. Podem ser considerados como testes informais para validaçãodos requisitos do sistema.

111

Tipos de cenários

Primários

São os cenários nos quais o fluxo segue normalmente. Não há quebrano fluxo por alguma espécie de erro.

Secundários

São os casos que compõem exceção. O fluxo normal de operação éinterrompido.

Definição de "Use case"

É um modelo das funções a serem executadas pelo sistema e ainteração com suas fronteiras. Sua principal aplicação é confirmar aosusuários e clientes as suas funcionalidades e comportamento.

Objetos e Classes de Objetos

Definição de Objeto

Representa um entidade que pode ser física, conceitual ou de software .É uma abstração de algo que possui fronteira definida e significado paraa aplicação.

Componentes de um objeto

• Estado• Comportamento• Identidade

Identidade: É o que identifica unicamente um objeto, mesmo que elepossua estados ou comportamento comuns a outros objetos.

Estado de um objeto: É cada condição na qual o objeto pode existir. Émutável ao longo do tempo. É implementado por um conjunto deatributos, os valores desses atributos e ligações que o objeto pode tercom outros objetos.

Comportamento de um objeto: Determina como um objeto age ereage a estímulos de outros objetos. É modelado através de um

112

conjunto de mensagens que representam resultados visíveis dasoperações executadas internamente pelo objeto.

Definição de Classe É uma descrição de um grupo de objetos comatributos, comportamentos, relacionamentos com outros objetos esemântica comuns. Uma classe é uma abstração que enfatizacaracterísticas relevantes dos objetos, suprimindo outras características.

Exemplo da Classe Curso

Nome:Curso

Estado:Nome

Número do CursoLocalizaçãoDias do CursoNúmero de créditosHora de InícioHora de Término

Comportamento: Comportamento:Adicionar um alunoCancelar um alunoObter alunos MatriculadosDeterminar se a turma está completa

Exemplo da Classe Professor

Nome:Professor

Estado:Nome

Número do EmpregadoData de AdmissãoCurso ministradoTipo de contrataçãoSalário

113

Comportamento:Consultar Lista de AlunosIndicar suas Disciplinas

A notação usada pela UML para representar uma Classe de Objetos é:

NomeAtributoOperações

A classe de objeto é representada por um retângulo, subdividido em trêsáreas. A primeira contém o nome da Classe. A segunda contém seusatributos. A terceira contém suas operações. A seguir, tem-se osexemplos que esclarecem a representação descrita acima.

Curso ProfessorNúmero do CursoNomeLocalizaçãoDias do CursoNúmero de CréditosHora de InícioHora de Término

Número do EmpregadoNomeData de AdmissãoCurso ministradoTipo de contrataçãoSalário

Adicionar um Aluno( )Cancelar um Aluno( )Obter Alunos Matriculados( )Determinar se a turma está completa( )

Consultar Lista de Alunos( )Indicar suas Disciplinas( )

Estereótipos

Estereótipo é um elemento de modelagem que rotula tipos de Classesde Objeto. Uma Classe de Objetos pode ter um ou mais tipos deestereótipos. Os estereótipos mais comuns são:

• Classe Fronteiriça• Classe de Entidade• Classe de Controle• Classe de Exceção• Metaclasse• Classe Utilitária

114

<<entidade>>Curso

<<entidade>>Professor

Número do CursoNomeLocalizaçãoDias do CursoNúmero de CréditosHora de InícioHora de Término

Número do EmpregadoNomeData de AdmissãoCurso ministradoTipo de contrataçãoSalário

Adicionar um Aluno( )Cancelar um Aluno( )Obter Alunos Matriculados( )Determinar se a turma está completa( )

Consultar Lista de Alunos( )Indicar suas Disciplinas( )

A notação usada pela UML para Estereótipos, dentro da representaçãográfica da Classe de Objeto, é colocá-lo entre << >> na área reservadapara o nome da classe e acima deste.

Classe fronteiriça . É uma classe que modela a comunicação entre avizinhança do sistema e suas operações internas.

Exemplos: Interface tipo Janela, Protocolo de Comunicação, Interface deImpressão, Sensores etc.

No presente estudo de caso, sistema automatizado de Matrícula numCurso, as classes de objeto Formulário em Branco e Sistema deCobrança são exemplos de estereótipos desta classe.

Classe de Entidade . É uma classe que modela objetos cuja informaçãoe o comportamento associados são, de maneira geral, persistentes.

No presente estudo de caso, sistema automatizado de Matrícula numCurso, as classes de objeto: Lista de Cursos, Curso, Catálogo eMatrícula, são exemplos de estereótipos desta classe.

Classe de Controle . É uma classe que modela o comportamento decontrole específico para uma ou mais "Use Case". Suas principaiscaracterísticas são:

• Cria, ativa e anula objetos controlados.• Controla a operação de objetos controlados

115

• Controla a concorrência de pedidos de objetos controlados.• Em muitos casos corresponde a implementação de um objeto

intangível.

No presente estudo de caso, sistema automatizado de Matrícula numCurso, a classe de objeto Gerente de Registro é um exemplo deestereótipo desta classe.

Interação entre objetos

A UML se utiliza de dois diagramas para representar a interação entreos objetos: Diagrama de Seqüência e Diagrama de Colaboração.

Diagrama de Seqüência

Mostra a interação entre os Objetos ao longo do tempo. Apresentandoos objetos que participam da interação e a seqüência de mensagenstrocadas.

A notação usada pela UML para representar o Diagrama de Seqüência,é a seguinte:

• Objetos são representados por retângulos com seus nomessublinhados.

• As linhas de vida dos Objetos são representadas por linhasverticais tracejadas.

• As interações entre Objetos são indicadas por flechashorizontais que são direcionadas da linha vertical querepresenta o Objeto cliente para a linha que representa o Objetofornecedor.

• As flechas horizontais são rotuladas com as mensagens.• A ordem das mensagens no tempo é indicada pela posição

vertical, com a primeira mensagem aparecendo no topo.• A numeração é opcional e baseada na posição vertical.

Foco de Controle

Representa o tempo relativo que o fluxo de controle esta focalizado numdado Objeto. Ele representa o tempo que um Objeto dedica a uma dadamensagem.

116

Diagrama de Colaboração

É um modo alternativo para representar a troca de mensagens entre umconjunto de Objetos. O Diagrama de Colaboração mostra a interaçãoorganizada em torno dos Objetos e suas ligações uns com os outros.

A notação usada pela UML para representar o Diagrama deColaboração, é a seguinte:

• Objetos são representados por retângulo com seus nomessublinhados.

• As interações entre Objetos são indicadas por uma linhaconectando-os.

• As ligações indicam a existência de um caminho paracomunicação entre os Objetos conectados.

• As ligações no Diagrama de Colaboração podem serapresentada por:¾ flechas apontando do Objeto cliente para o Objeto

fornecedor;¾ nome da mensagem;¾ numeração seqüencial, mostrando a ordem relativa de

envio das mensagens.

Como Descobrir as Classes de Objetos

Análise do "Use Case"

É o processo de examinar o conjunto de "Use Cases " para extrair osObjetos e Classes do sistema sob desenvolvimento. Os Objetos eClasses não podem ser obtidos do detalhamento dos Cenários(instâncias de "Use Case ").

Cenário para criar matrícula

Cleber entra com o número de identificação do aluno 369 53 3449 eo sistema valida o número . O sistema pergunta a qual semestrerefere-se a matrícula. Cleber indica que é para o semestre atual eescolhe a opção "nova matrícula ".

Da lista de cursos disponíveis , Cleber seleciona como cursos deprimeira escolha : Engenharia de Softwarwe , SistemasComputacionais Cliente Servidor , Tópicos em Análise Orientada aObjetos 200 e Gerência de Mainframe 110 . Ele seleciona como

117

cursos de segunda escolha : Introdução à Programação Java 200 eTeoria da Música 300 .

O sistema verifica que Cleber tem todos os pré-requisitosnecessários , examinando os registro do aluno e adiciona-o à lista dealunos do curso .

O sistema indica que a atividade está completa. O sistema imprime amatrícula e envia a informação de cobrança , referente aos quatrocursos , para processamento no sistema de cobrança .

Objetos pertencente à Classe de Entidades

São identificados examinando-se os substantivos e frasessubstantivadas no cenário. No cenário acima estão destacados ossubstantivos candidatos a Objetos da Classe de Entidade. Ossubstantivos podem ser: Objetos, descrição do estado de um Objeto,entidade externa e/ou ator ou ainda nenhuma das anteriores.

Lista de substantivos e sua classificação

Cleber –– atornúmero de identificação do aluno 369 53 3449 –– propriedade dealunosistema –– o que está sendo definidonúmero –– propriedade do alunosemestre –– estado (que é selecionado quando aplicável)semestre atual –– mesmo que semestrenova matrícula –– Objeto candidatolista de cursos disponíveis –– Objeto candidatocursos de primeira escolha –– estadoEngenharia de Softwarwe –– Objeto candidatoSistemas Computacionais Cliente Servidor –– Objeto candidatoTópicos em Análise Orientada a Objetos 200 –– Objeto candidatoGerência de Mainframe 110 –– Objeto candidatocursos de segunda escolha –– estadoIntrodução à Programação Java 200 –– Objeto candidatoTeoria da Música 300 –– Objeto candidatopré-requisitos necessários –– cursos com outra identificaçãoregistro do aluno –– Objeto candidatolista de alunos do curso –– Objeto candidatoatividade –– expressãomatrícula –– mesmo que nova matrícula

118

informação de cobrança –– Objeto candidatoquatro cursos –– informação necessária ao sistema de cobrançasistema de cobrança –– ator

Lista de Objetos da Classe Entidade

nova matrícula –– Lista de cursos para um dado semestre de um dadoalunolista de cursos disponíveis –– Lista de todos os cursos que estãosendo oferecidos no semestreEngenharia de Softwarwe –– Um curso oferecido no semestreSistemas Computacionais Cliente Servidor –– Um curso oferecido nosemestreTópicos em Análise Orientada a Objetos –– Um curso oferecido nosemestreGerência de Mainframe –– Um curso oferecido no semestreIntrodução à Programação Java –– Um curso oferecido no semestreTeoria da Música –– Um curso oferecido no semestreregistro do aluno –– Lista dos cursos feitos pelo aluno nos semestresanterioreslista de alunos do curso –– Lista com os alunos matriculados numcurso específico.informação de cobrança –– Informações necessárias para o atorsistema de cobrança.

Criando as Classes de Entidades

Baseando-se na similaridade de estrutura e de comportamento dosobjetos.

Lista de Classes de Entidades presentes no Cenário "CriarMatrícula"

• Matrícula – Lista dos cursos para um dado semestre para umdado aluno.

• Catálogo – Lista de todos os cursos oferecidos em umsemestre.

• Curso – Curso oferecido para um semestre.• RegistroDoAluno – Lista dos cursos feitos anteriormente.• ListaDosAlunosNumCurso – Lista dos alunos matriculados em

um curso específico.• InformaçõesDeCobrança – Informações necessárias para o ator

sistema de cobrança.

119

Objetos pertencentes à Classe Fronteiriça

São identificados examinando-se cada par ator/cenário e criando-se asclasses fronteiriças óbvias. Classes Fronteiriças também são criadaspara comunicação sistema/sistema e para descrever a escolha deprotocolos de comunicação.

Exemplos de classe fronteiriça:

• Deve ser apresentado ao aluno, mais de uma opção do "UseCase" "Matrícula nos Cursos ". Para tanto, é criada a Classe"FormulárioDeRegistro " para permitir ao estudante selecionara opção desejada.

• O aluno deve fornecer ao sistema a informação dos cursosescolhidos. Para tanto é criada a Classe"FormulárioDeMatrícula " para permitir que o aluno entre com ainformação.

• A matrícula do aluno é impressa. Para tanto é criada a Classe"Impressora ".

• A informação de cobrança é enviada para o sistema decobrança. Para tanto, é criada a Classe "SistemaDeCobrança ".

Objetos pertencente à Classe de Control

Tipicamente, contêm a informação de seqüenciamento. Cada "UseCase" deve ter uma Classe de Controle, responsável pelo fluxo deeventos. Para tanto, é criada a Classe "GerenteDeRegistro ". Essaclasse, para cada curso selecionado na Classe Fronteiriça"FormulárioDeMatrícula " deve executar as seguintes atividades:

• Busca na Classe Curso seus pré-requisistos.• Verifica, através da Classe RegistoDoAluno se todos os pré-

requsisitos do curso selecionado foram satisfeitos.• Sabe o que fazer se um pré-requisito não foi satisfeito.• Interroga se há vaga no curso.• Se houver vaga, pede a classe ListaDeAlunosNoCurso para

adicionar o aluno.• Sabe o que fazer se um dos quatro cursos não está disponível.• Cria os objetos: MatrículaDoAluno e InformaçãoDeCobrança .• Verifica se o sistema de cobrança está habilitado a receber a

informação de cobrança.

120

Cartão Class-Responsibility-Collaboration (CRC)

Novas Classe podem ser descoberta através do uso do cartão CRC. UmCRC é um cartão que contém:

• Nome e descrição da Classe.• As responsabilidades da Classe:

¾ Conhecimento interno da Classe;¾ Serviços fornecidos pela Classe.

• Os colaboradores com essas responsabilidades:¾ Um colaborador é uma classe cujos serviços são

necessários para execução de dada responsabilidade.

Nome da Classe: CursoResponsabilidade ColaboradoresAdicionar Aluno (incrementar o no. vagaspreenchidas)

Aluno

Conhecer pré-requisitosConhecer quando o curso é dadoConhecer onde o curso é dado

Uma sessão com o uso do cartão CRC compreende

• Um grupo de pessoas é escolhido para representar um cenário.• É criado um cartão para cada Classe de Objeto já identificado

dentro desse cenário.• A cada participante é associada uma Classe, de modo que cada

pessoa torna-se aquela Classe.• Um cenário é encenado pelos participantes.• Os cartões são preenchidos com as responsabilidades e os

colaboradores.• Novos cartões são criados para classes de Objetos descobertos

na sessão.

Benefícios do uso do cartão CRC

• À medida que os cenários são encenados, padrões decolaboração emergem.

• Os cartões que colaboram entre si podem ser arranjadosfisicamente próximos.

121

• Esse arranjo ajuda a identificar hierarquias de generalização/especialização ou agregação entre as classes.

• O uso do cartão CRC é mais efetivo para grupo iniciantes nouso de técnicas OO.

O uso do cartão CRC permite

• Confirmar ou não as classes de objetos candidatas, além depermitir a descoberta de novas Classes.

• Determinar o relacionamento entre as Classes.• Identificar atributos (conhecimento interno) e operações

(serviços fornecidos).

À medida que Classes de Objetos são descobertas, elas sãodocumentadas nos diagramas de interação (diagramas de seqüência ede colaboração) anteriormente confeccionados.

Pacote

As classes pertencentes ao Sistema de Matrícula podem ser agrupadasem três pacotes:

• ElementosDaUniversidade• Matrícula• Curso• RegistroDeAluno• Catálogo• ListaDosAlunosNumCurso• InformaçõesDeCobrança• RegrasDeNegócio• GerenteDeRegistro• Interfaces• FormulárioDeRegistro• FormulárioDeMatrícula• Impressora• SistemaDeCobrança

Definição de Pacote

É uma generalização com o propósito de organizar as Classes deObjetos em grupos. Esta abordagem facilita a análise à medida que o

122

número de Classes de Objetos cresce em um do cenário.

A notação usada pela UML para representar pacotes é:

Relacionamentos

Definição de relacionamento

É a maneira como as Classes de Objetos interagem entre si para formaro comportamento do sistema. Esse relacionamento é apresentadoatravés de Diagrama de Classes. Os dois principais tipos derelacionamento são associação e agregação.

Associação

• É uma conexão bidirecional entre Classes que indica aexistência de um relacionamento entre os objetos dessasClasses.

• É representada, nos Diagramas de Classe, por uma linhaconectando as Classes associadas.

• O fluxo de dados pode ser unidirecional ou bidirecional, atravésda conexão.

• Para esclarecer o significado de uma associação, ela énomeada. No Diagrama de Classes, o nome é apresentado aolongo da linha de associação. Usualmente, esse nome é umverbo ou um frase verbalizada.

• Entre duas Classes, podem existir mais de uma associação.

Multiplicidade de Associação

• É o número de instâncias de uma classe relacionada com umainstância de outra classe.

• Para cada associação, há uma multiplicidade em cada direção.

Associação Reflexiva

É quando os Objetos da própria Classe estão se relacionando.

Agregação

• É uma forma especializada de associação na qual um todo érelacionado com suas partes. Também conhecida como relaçãode conteúdo.

123

• É representada como uma linha de associação com umdiamante junto à Classe agregadora.

• A multiplicidade é representada da mesma maneira que nasassociações.

Um objeto da Classe FormulárioDeRegistro contém um único objetoFormulárioDeMatrícula . Um objeto FormulárioDeMatrícula estácontido num único objeto FormulárioDeRegistro .

Agregação Reflexiva

É quando Objetos de uma Classe é composto de Objetos da própriaClasse.

Classe de uma Associação de Classe

Permite adicionar atributos, operações e outras características a umadada associação.

A classe de uma Associação de Classe normalmente é gerada a partirde uma associação de muitos para muitos.

Relacionamento entre Pacotes

• Pacotes são relacionados uns com os outros usando umrelacionamento de dependência.

• Se uma Classe de um pacote interage com uma Classe deoutro pacote, a relação de dependência é adicionada a nível depacote.

• Relacionamento entre pacotes são obtidos a partir dosdiagramas de Classe e de Cenário.

Operações e Atributos

Definição de Operações

São procedimentos que executam as responsabilidades de uma Classede Objetos e portanto definem o comportamento dos objetos da Classe.

Uma operação é um serviço que pode ser requisitado por um Objetopara realizar um comportamento. Operações devem ser nomeadas em

124

função de suas saídas e não em função de seus passos internos.

Definição de Atributos

São dados que caracterizam uma instância da Classe de Objetos.Atributos não tem comportamento. Atributos são sempre valorados.

Cada valor de um atributo é particular para um dado objeto. Atributossão nomeados por substantivo simples ou por verbo substantivado.Cada atributo tem uma definição concisa e clara.

A notação usada pela UML é apresentar Atributos no segundocompartimento da Caixa de representação de Classe de Objetos,conforme mostra a figura acima.

Cada atributo tem tipo do dado e valor inicial, por exemplo, o tipo dedado para o atributo horário é: hh:mm:ss e o valor inicial é 00:00:00 .

A determinação dos atributos de uma Classe de Objetos pode serconseqüência de:

• Análise dos fluxos de evento nos "Use Case ".• Definição de uma Classe de Objetos.• Conhecimento do sistema.

Comportamento

O comportamento de uma Classe de Objetos é representado através deum Diagrama de Transição de Estado, que descreve o ciclo de vida deuma dada classe, os eventos que causam a transição de um estadopara outro e as ações resultantes da mudança de estado.

O espaço amostral dos estados de uma dada Classe corresponde àenumeração de todos os estados possíveis de um objeto.O estado de um Objeto é uma das possíveis condições na qual o objetopode existir. O estado compreende todas as propriedades dos objetos(estáticas) associadas aos valores correntes (dinâmico) de cada umadessas propriedades.

Estados e Atributos

Estados podem ser distinguidos pelos valores assumidos por certosatributos.

125

Por exemplo, o número máximo de estudantes por curso, no "Use Case "Matrícula do Aluno, é igual a 10.

Estados e Ligações

Estados também podem ser distinguidos pela existência de certasligações.

Exemplo

A instância da Classe Professor pode ter dois estados:

• Ensinando –– quando o Professor está ministrando um Curso.• Licenciado –– quando não está ministrando nenhum Curso.

Estados Especiais

Estado Inicial

É o estado atribuído a um objeto quando é criado. O estado Inicial temas seguintes características:

• É mandatório.• Somente um estado Inicial é permitido.• O estado Inicial é representado por um círculo preenchido.

Estado Final

É o estado que indica o fim do ciclo de vida de um objeto. O estado Finaltem as seguintes características:

• É opcional.• Pode existir mais de um estado final.• estado Final é representado por um "olho de boi ".

Eventos

Um evento é uma ocorrência que acontece em algum ponto no tempo eque pode modificar o estado de um objeto, podendo gerar uma resposta.

126

Exemplo

• Adicionar um aluno a um curso.• Criar um novo curso.

Transição

É a mudança do estado atual para o estado subseqüente comoresultado de algum estímulo. O estado subseqüente pode ser igual aoestado original. Uma transição pode ocorrer em resposta a um evento.As transições rotuladas com o nome dos eventos.

Condição de Guarda

A condição de guarda é uma expressão booleana de valores de atributoque permitem que a transição ocorra somente se a condição assumidapela expressão é verdadeira.

Ações

É uma operação que está associada a uma transição, ocorrendoinstantaneamente e que não pode ser interrompida. Nome de uma açãoé mostrado, na seta indicativa da transição, precedida por um barrainclinada (/).

Envio de eventos a partir de outro evento

Um evento pode provocar o envio de outro evento. O nome do eventoenviado é mostrado, na seta indicativa de transição, precedido por umcircunflexo (^) seguido pelo nome da Classe para onde o evento seráenviado, separados por um ponto.

Exemplo

Evento1^Classe.Evento2 , onde Evento1 é o evento que causou atransição e Evento2 é o evento gerado a partir da transição.

Atividade

É uma operação que está associada a um estado, leva um tempo paraser executada e que pode ser interrompida.

127

Envio de eventos a partir de atividade

Uma atividade também pode provocar o envio de um evento para umoutro Objeto.

Transição Automática

Algumas vezes, o único propósito da existência de um estado édesenvolver uma atividade. Uma transição automática ocorre quando aatividade é completada. Se múltiplas transições automáticas existem,uma condição de guarda é necessária para cada transição e ascondições de guarda devem ser mutuamente exclusivas.