Anda di halaman 1dari 24

Universidade Federal de Mato Grosso do Sul

o Facom - Faculdade de Computac a


o Orientada a Objetos Linguagem de Programac a Prof. Me. Liana Duenha

Fundamentos da Programa c ao Orientada a Objetos


Neste t opico da disciplina, iniciaremos o estudo sobre o paradigma de programa ca o orientada a objetos utilizando linguagem C++ para implementa c ao dos exemplos e primeiros programas. Esse material e baseado nas notas de aula dos professores Paulo Pagliosa e Anderson Bessa, e livro texto How To Program (Deitel).

Motiva c ao

Em meados de 1970, pesquisadores da XEROX PARC desenvolveram a linguagem Smalltalk, a primeira totalmente orientada a objetos. No in cio da d ecada de 80, a AT&T lan cou a Linguagem C++, uma evolu c ao da linguagem C com recursos para programa ca o orientada ` a objetos. Atualmente, a grande maioria das linguagens incorpora caracter sticas de OO, como Java, Object Pascal e C#. A an alise, projeto e programa ca o orientadas a objetos s ao respostas ao aumento da complexidade dos ambientes computacionais que se caracterizam por sistemas heterog eneos, distribu dos em redes, em camadas e baseados em interfaces gr acas. A programa ca o orientada a objetos e uma evolu ca o de pr aticas que s ao recomendadas, mas n ao formalizadas, na programa c ao estruturada. A grande diculdade para compreender a programa c ao OO e a diferen ca de abordagem do problema. Enquanto a programa ca o estruturada tem como principal foco as a co es (procedimentos e fun c oes), a programa ca o OO se preocupa com os objetos e seus relacionamentos; As principais vantagens da programa ca o OO s ao: facilitar a modelagem do problema, extensibilidade, reusabilidade, produtividade e recursos para prote ca o dos dados. Os recursos da programa ca o OO que ser ao estudados nessa disciplina s ao: encapsulamento, heran ca, sobrecarga de operadores, polimorsmo, e boas pr aticas de programa ca o. Utilizamos linguagem C++ para exemplicar os conceitos de OO e, na segunda parte da disciplina, aprenderemos como obter os mesmos recursos usando a Lingaugem Java e as diferen cas fundamentais entre as duas linguagens.

Classes e Objetos

Um objeto e um modelo computacional de uma entidade concreta ou abstrata, denido por um conjunto de atributos (eventualmente vazio) e capaz de executar um conjunto de opera c oes ou m etodos. Os atributos de um objeto representam os dados que caracterizam a estrutura da entidade; os m etodos executam sobre os atributos e denem o comportamento da entidade. Uma classe e uma descri c ao dos atributos e dos m etodos de um determinado tipo de objeto. Denida uma classe pode-se, a partir dela, instanciar objetos daquele tipo. Um objeto e uma inst ancia de uma classe. Em uma classe, declaram-se atributos e m etodos que descrevem, respectivamente, as caracter sticas e o comportamento dos objetos instanciados.

2.1

Denindo uma classe

Iniciamos com um exemplo de deni c ao de uma classe para descrever ou modelar n umeros complexos. Um n umero complexo z e um n umero que pode ser escrito na forma z = a + ib, onde a e b s ao n umeros reais e i denota a unidade imagin aria 2 com propriedade i = 1. a e b s ao chamados, respectivamente, parte real e parte imagin aria de z . O conjunto dos n umeros complexos cont em o conjunto dos n umeros reais. Dentre as poss veis opera co es sobre n umeros complexos, escolhemos as mais simples para especica c ao deste nosso primeiro exemplo. Segue, ent ao, a descri ca o da classe Complex. class Complex { public: float a; // parte real float b; // parte imagin aria // construtor default Complex() { a = 0; b = 0; } Complex(float a1, float b1 = 0) { a = a1; b = b1; }

// construtor de c opia (rasa) Complex(const Complex& c) { a = c.a; b = c.b; } Complex add (const Complex& c) const; Complex sub (const Complex& c) const; // ... demais m etodos da classe Complex }; // Complex

Para denir uma classe utilizamos a palavra reservada class seguida do nome da classe. Por conven ca o, o nome de uma classe denida pelo usu ario inicia com uma letra mai uscula e, por legibilidade, cada palavra subsequente no nome da classe inicia com uma letra mai uscula. O corpo de uma classe e colocado entre um par de chaves esquerda e direita. A deni ca o da classe termina com ponto e v rgula. Um erro bastante comum durante a programa c ao e esquecer do ponto e v rgula ap os a deni c ao da classe. Especicadores de acesso Logo ap os a linha onde denimos o nome da classe utilizamos um especicador de acesso public: para indicar que os atributos ou m etodos descritos em seguida podem ser utilizados por outros m etodos do programa ou fun co es membro de outras classes. Um outro especicador de acesso que n ao est a sendo utilizado nesse exemplo e denominado private:. Esse especicador de acesso informa que os atributos e/ou m etodos que seguem esse especicador s ao acess veis apenas aos m etodos da classe em que foram denidas. Se nenhum especicador de acesso for usado, todos os membros de dados e m etodos s ao declarados como privados (private) por padr ao. Estes e outros especicadores de acesso ser ao estudados mais profundamente em se c oes seguintes. Atributos No exemplo, ap os o especicador de acesso, h a a descri c ao dos atributos ou membros de dados. Os atributos denidos s ao dois n umeros reais, denominados a e b , que representam a parte real e imagin aria, respectivamente, do objeto sendo instanciado. M etodos Construtores Seguindo a descri ca o da classe no exemplo, h a dois m etodos com o mesmo nome da classe denominados construtores da classe. Um construtor e um m etodo que e invocado automaticamente sempre que um objeto da classe for criado. Geralmente, utilizamos um construtor para realizar a inicializa ca o dos atributos da classe em

quest ao, por em pode-se tamb em realizar no construtor quaisquer a c oes que se zerem necess arias, tais como aloca c ao de mem oria, abertura de arquivos, envio de mensagens via rede, impress ao na tela, etc. Um construtor tem obrigatoriamente o mesmo nome da classe e n ao tem tipo de retorno (nem mesmo void). Quando o programador n ao descreve um construtor default, o compilador fornece um. Uma classe pode declarar v arios construtores, desde que distinguidos pelo n umero e/ou tipo de par ametros formais. Um construtor que e declarado sem quaisquer par ametros e chamado construtor default. No nosso exemplo, o primeiro construtor n ao possui par ametros de entrada e apenas atribui 0 aos atributos a e b do objeto que est a sendo criado. O segundo construtor diferencia-se do primeiro apenas por ter dois par ametros ou argumentos. O primeiro argumento e um valor real que ser a atribu do ao atributo a do objeto. O segundo par ametro e um valor real que, quando informado, ser a atribu do ao atributo b . A sintaxe float y=0 informa para o compilador que quando o segundo par ametro for omitido, o valor 0 deve ser atribu do a y e posteiormente, ao atributo b . O u ltimo dos construtores do exemplo e chamado construtor de c opia que e caracterizado por ter apenas um par ametro cujo tipo e uma refer encia para um objeto constante da pr opria classe. O par ametro e constante pois seus atributos n ao s ao alterados dentro do corpo do construtor. O prop osito de um construtor de c opia e inicializar atributos do ojbeto rec em-criado com uma c opia dos atributos do objeto referenciado pelo par ametro. Estudaremos procedimentos de c opia rasa e profunda em se c oes posteriores. Demais M etodos Os m etodos declarados na classe representam o comportamento de um objeto desta classe. Em C++, a implementa c ao, ou seja, a deni c ao do corpo, de um m etodo declarado em uma classe pode ser efetuada dentro da classe ou fora da classe. Na classe Complex, os construtores foram implementados dentro da classe e os m etodos add e sub foram apenas declarados e ser ao implementados fora da classe. Um m etodo implementado fora da classe no qual foi declarado deve ser identicado atrav es de seu nome qualicado. O nome qualicado de um m etodo m() declarado em uma classe X e X::m(), onde o nome X e chamado qualicador, o nome m e chamado nome simples e :: e o operador de escopo de C++. Desta forma, a implementa ca o do m etodo add fora da classe Complex teria a seguinte sintaxe: Complex Complex::add (const Complex& c) const { ... }

Ciclo de Vida de um Objeto

Em programa c ao orientada a objetos (POO) a computa ca o ocorre em um universo constitu do de objetos que trocam mensagens entre si. Dentro desse universo, objetos s ao criados, possuem um tempo de vida u til e s ao destru dos ao longo da computa c ao. O ciclo de vida de um objeto consiste na cria c ao (ou instancia ca o), uso e destrui ca o do objeto.

3.1

Cria c ao de objetos

Em C++, um objeto pode ser criado de duas maneiras: estaticamente e dinamicamente. Para se criar um objeto de forma est atica, basta declarar uma vari avel cujo tipo e a classe do objeto. Seguem formas diferentes de instanciar estaticamente um objeto da classe Complex: Complex c1; // invoca construtor default Complex c2(); // idem Complex c3(5); // invoca Complex(float,float), c3.a=5 e c3.b=0 Complex c4(3,4); // invoca Complex (float,float), c4.a=3 e c4.b=4 Complex c5(c4); // invoca construtor de c opia Complex c6=c5; //idem Um objeto pode ser alocado dinamicamente utilizando o operador new, oferecido pelo compilador C++. A diferen ca fundamental e que o objeto ocupar a espa co na a rea de heap do programa e ser a acessado por meio de um ponteiro. No caso da classe Complex, podemos citar alguns exemplos de uso do operador new para cria c ao din amica do objeto. Na declara c ao Complex *p = new Complex();, p e um ponteiro para um objeto da classe Complex, cujo valor e o endere co de uma inst ancia de Complex, dinamicamente criada com o operador new. Tamb em podemos utilizar as v arias vers oes dos construtores dispon veis para criar objetos dinamicamente. Alguns exemplos: Complex *p = new Complex; // new retorna um ponteiro para um objeto Complex Complex *p = new Complex(3,4); // new retorna um ponteiro para uma inst^ ancia de Complex, criada por meio do construtor Complex(float, float)

int *x = new int(); // new retorna um ponteiro para inteiro int *vet = new int[10]; // new retorna um ponteiro para um array de 10 inteiros A cria c ao de um objeto, seja est atica ou din amica, envolve: 1. Aloca c ao de espa co na mem oria para armazenamento dos valores dos atributos do objeto, atributos esses declarados na classe do objeto. Um objeto criado estaticamente tem mem oria reservada em tempo de compila ca o, no seguimento de dados ou no segmento de pilha do programa, caso o objeto tenha sido criado com uma declara ca o de vari avel global ou local (ou seja, em um bloco de fun ca o), respectivamente. Um objeto criado dinamicamente tem mem oria alocada em tempo de execu c ao na a rea de heap do programa. 2. Inicializa c ao do objeto realizado por meio da execu ca o do c odigo descrito em um dos m etodos construtores da classe. Al em da leitura sobre destrui ca o de objetos, n ao deixe de ler a se ca o 13 para entender como liberar mem oria alocada previamente para um objeto.

3.2

Uso de objetos

O uso de um objeto pode ser por meio ao acesso aos seus atributos ou aos seus m etodos. A sintaxe utilizada para usar objetos depende da forma como foram instanciados. Seguem exemplos de acesso aos atributos dos objetos c e p da classe Complex criados, respectivamente, de maneira estatica e dinamica: float x = c.a; // acesso ao atributo a do objeto c float y = c.b; // acesso ao atributo b do objeto c float t = p->a; // acesso ao atributo a do objeto p float v = p->b; // acesso ao atributo b do objeto p Declarados os m etodos que um objeto pode executar, outra maneira de usar um objeto e enviar a este uma mensagem. Uma mensagem e uma solicita ca o feita a um objeto para que este execute uma determinada opera ca o. Para exemplicar, seja um ojbeto x da classe X, criado estaticamente. O envio de uma mensagem a x tem a seguinte sintaxe em C++: x.m(1,2,3);

onde o objeto x e chamado receptor da mensagem, m e o seletor da mensagem e (1,2,3) e a lista de argumentos da mensagem. Em resposta a uma mensagem, o objeto deve executar um m etodo. No exemplo acima, o m etodo a ser executado ser a aquele declarado na classe X cujo nome e m e cujo n umero e tipo de par ametros s ao compat veis com o n umero e tipo dos argumentos da mensagem. O mecanismo de sele ca o de um m etodo, em resposta a uma mensagem enviada a um objeto, e chamado acoplamento mensagem/m etodo. Complex c3 = c1.add(c2); // c1 e receptor, add e seletor e c2 e argumento da mensagem Complex c6 = c4.sub(c5); // c4 e receptor, sub e seletor e c5 e argumento da mensagem Nesses dois casos, o argumento do construtor de c opia usado na inicializa c ao dos objetos c3 e c6 s ao resultados das mensagens c1.add(c2) e c4.sub(c5), respectivamente.

3.3

Destrui c ao de Objetos

Ap os o uso os objetos s ao destru dos. A destrui c ao envolve as seguintes opera c oes (inversas das opera c oes realizadas na cria c ao): naliza c ao do objeto e libera ca o da mem oria utilizada pelos atributos do objeto. A naliza ca o do objeto e efetuada por um m etodo especial declarado na classe do objeto chamado destrutor. O nome do destrutor de uma classe e o caractere tilseguido pelo nome da classe. O c odigo do destrutor deve ser respons avel pela limpeza da mem oria utilizada (por exemplo, fechamento de arquivos, libera c ao de mem oria e dos demais recursos alocados pelo objeto na cria c ao ou ao longo da vida u til, etc.). O destrutor em si n ao libera a mem oria do objeto. Esse m etodo especial n ao recebe argumentos e n ao retorna valor algum. S o pode haver um destrutor declarado em uma classe. Em C++, o compilador prov e um destrutor se um n ao for declarado, cujo corpo e vazio, ou seja, que n ao faz nada. O momento de destrui ca o de um objeto depende de como este foi criado. Objetos criados estaticamente s ao automaticamente destru dos quando cessa o tempo de vida do escopo no qual foram criados. Ou seja, objetos autom aticos locais s ao destru dos quando o uxo de execu ca o e transferido para fora do bloco onde foram declarados; objetos globais s ao automaticamente destru dos ao t ermino da execu c ao do programa. Objetos criados dinamicamente t em que ser explicitamente destru dos com o operador delete (em C++ n ao h a coleta de lixo para destrui ca o autom atica desses objetos). A se ca o 13 mostra como liberar mem oria previamente alocada de forma din amica.

Os destrutores n ao s ao chamados para objetos autom aticos se o programa terminar com uma chamada a ` fun c ao exit() ou abort().

Arquivos de cabe calho e arquivos de c odigo-fonte

Ao construir um programa orientado a objetos utilizando a linguagem C++, e comum denir as classes em um arquivo que, por conven ca o, tem uma extens ao de nome de arquivo .h (conhecido como arquivo de cabe calho). No nosso exemplo, a deni ca o da classe Complex est a em um arquivo com nome Complex.h . Por conven ca o, descri ca o dos m etodos destas classes (ou seja, a implementa c ao destes m etodos em si) deve car em um arquivo separado, cujo nome e o mesmo do arquivo de cabe calho por em com extens ao .cpp (no nosso exemplo, Complex.cpp). Este arquivo deve conter a diretiva de pr e-processador #include para incluir os arquivos de cabe calho necess arios. No caso da inclus ao do arquivo de cabe calho Complex.h a diretiva correta seria #include "Complex.h" (arquivo de cabe calho criado pelo usu ario entre aspas). Al em da descri c ao das classes e da implementa ca o dos m etodos da classe, temos ainda o c odigo-cliente, ou seja, a fun ca o main que de fato declara e utiliza os obje comum que esse c tos requeridos pela aplica c ao em quest ao. E odigo que em um terceiro arquivo com extens ao .cpp. Desta forma, temos c odigo-fonte reutiliz avel, j a que a deni c ao das classes e a implementa c ao de seus m etodos est ao em arquivos independentes do c odigo-cliente, ou seja, do c odigo que dene como a aplica ca o deve comportar-se.

Processo de Compila c ao e Link-edi c ao

Um programador respons avel por criar a classe Complex reutiliz avel cria o arquivo de cabe calho Complex.h e o arquivo de c odigo-fonte Complex.cpp que inclui o arquivo de cabe calho (#include) e, depois, compila o arquivo de c odigo-fonte para criar c odigoobjeto de Complex. O programador do c odigo-cliente pode nem ter conhecimento do arquivo de c odigo-fonte e ainda assim utilizar todas as funcionalidades da classe Complex sem diculdade. O c odigo-cliente s o precisa conhecer a interface de Complex para utilizar a classe e deve ser capaz de linkar ou ligar seu c odigo-objeto. A sa da do link-editor ou linker e o aplicativo execut avel. O diagrama da Figura 1 mostra o processo de compila c ao e link-edi c ao que resulta em um aplicativo Complex execut avel.

Arquivo de implementacao arquivo.cpp

Interface da Classe arquivo.h

Funcao main codigo cliente main.cpp

compilador

compilador

Codigo objeto da classe

Codigo objeto da funcao main

linker

Aplicativo executavel

Figura 1: Processo de compila ca o e link-edi c ao de para produzir um aplicativo execut avel.

Utilizando o ponteiro this

Vimos que os m etodos de uma classe podem manipular dados de um objeto instanciado. Por em, como indicamos sobre qual objeto o m etodo em quest ao deve manipular estes dados? O ponteiro this e passado pelo compilador como um argumento impl cito para cada um dos m etodos do objeto. Os objetos utilizam o ponteiro this implicitamente ou explicitamente para referenciar seus atributos e m etodos. Segue um exemplo de uso do ponteiro this. Complex(const Complex& c) { this->a = c.a; this->b = c.b; } Nesse caso, o uso do ponteiro this n ao e obrigat orio, j a que n ao h a ambiguidade quanto aos dados que devem ser acessados. J a no caso seguinte, uma modica c ao do construtor da classe Complex, o uso de this e essencial pois diferencia os atributos a e b do objeto receptor da mensagem (objeto rec em-criado) dos argumentos a e b.

Complex(float a, float b = 0) { this->a = a; this->b = b; }

Sobrecarga de Operadores

Em C++, o nome de um m etodo pode ser baseado em um operador da linguagem (a maioria dos operadores pode ser usada para este m, com exce c ao dos operadores ., .*, :: e ?:). Este recurso sint atico e chamado sobrecarga de operador. Um operador sobrecarregado e um m etodo cujo nome e formado pela palavra reservada operator seguida do s mbolo do operador que se deseja sobrecarregar. Os par ametros formais do m etodo devem ser compat veis com o tipo de operador, obrigatoriamente. O valor de retorno do m etodo deve opcionalmente ser compat vel com a sem antica do operador. Na classe Complex previamente denida, os m etodos de adi ca o e subtra c ao j a est ao implementados, mas podem ser substitu dos pelos operadores + e - sobrecarregados. class Complex { ... Complex operator +(const Complex &c) const // add { return Complex(a + c.a, b + c.b); } Complex operador -(const Complex &c) const // sub { return Complex(a - c.a, b - c.b); } ... }; Uma vez sobrecarregados os operadores + e - na classe Complex pode-se escrever: Complex c4 = c1.operator +(c2); Complex c5 = c3 + c4; // Complex c5 = c3.operator +(c4); Na u ltima declara ca o acima, c3 + c4 parece ser uma express ao aritm etica do tipo adi ca o cujos operandos s ao dois n umeros complexos. Por em, a express ao e, de fato, um

10

envio da mensagem cujo seletor e operator + e cujo argumento e c4 ao receptor c3. Em resposta, o m etodo Complex::operator +(const Complex &) const e acoplado e ent ao invocado. Observe que o operador + e bin ario, ou seja, requer dois operandos. No m etodo acima, estes dois operandos s ao: o objeto *this, receptor da mensagem (sendo this implicitamente passado como argumento pelo compilador), e o objeto c cuja refer encia deve ser explicitamente passada como argumento na mensagem. Em C++, um m etodo const e aquele que n ao altera os atributos do objeto apontado por this, ou seja, do receptor da mensagem. O modicador const faz parte da assinatura do m etodo, ou seja, dois m etodos com o mesmo nome simples e mesmo n umero e tipo de par ametros, um deles const e outro n ao, s ao m etodos distintos.

M etodos inline

Um m etodo implementado dentro de sua classe e inline por deni ca o; um m etodo declarado fora da classe n ao e inline a n ao ser que o modicador inline preceda a assinatura do m etodo. Uma fun c ao ou m etodo m() inline informa ao compilador para que este tente, na gera ca o de c odigo nas chamadas de m(), substituir a chamada por uma expans ao em linhado corpo de m(). A chamada de uma fun c ao ou m etodo inline (caso o compilador consiga fazer a expans ao em linha), elimina o overhead da passagem de argumentos e saltos de ida e de volta de uma chamada de fun ca o ou m etodo n ao inline, mas, em contrapartida, se o c odigo do corpo do m etodo for muito grande e houver muitas chamadas a m(), o c odigo nal tende a car maior. Portanto, fun co es ou m etodos inline devem ser usados com crit erio. Como o corpo de uma fun c ao ou m etodo inline deve ser conhecido no momento de uma chamada da fun ca o ou m etodo, a implementa ca o deste e comumente efetuada em um arquivo de cabe calho (.h). Por exemplo, os operadores sobrecarregados podem ser implementados como inline no arquivo Complex.h, ap os a deni c ao da classe. class Complex { ... Complex operator + (const Complex &); ... }; inline Complex Complex::operator +(const Complex& c) const { return Complex(a + c.a, b + c.b); }

11

Vers ao Final da Classe Complex

Como o que estudamos at e agora, podemos nalizar o arquivo Complex.h com a descri ca o da classe Complex e implementa ca o dos seus m etodos (todos inline).

#ifndef __Complex_h #define __Complex_h class Complex { public: float a; // parte real float b; // parte imagin aria // construtor Complex(float a1 = 0, float b1 = 0) { a = a1; b = b1; } // construtor de c opia (rasa) Complex(const Complex& c) { a = c.a; b = c.b; } // C opia (rasa) Complex& operator =(const Complex&); // Complex add (const Complex& c) const; // Complex sub (const Complex& c) const; Complex operator +(const Complex&) const; Complex operator -(const Complex&) const; Complex& operator +=(const Complex&); Complex& operator -=(const Complex&);

12

bool operator ==(const Complex&) const; bool operator !=(const Complex&) const; void print() const; }; // Complex inline Complex& Complex::operator =(const Complex& c) { a = c.a; b = c.b; return *this; } inline Complex Complex::operator +(const Complex& c) const { return Complex(a + c.a, b + c.b); } inline Complex Complex::operator -(const Complex& c) const { return Complex(a - c.a, b - c.b); } inline Complex& Complex::operator +=(const Complex& c) { a += c.a; b += c.b; return *this; } inline Complex& Complex::operator -=(const Complex& c) { a -= c.a; b -= c.b; return *this; } inline bool Complex::operator ==(const Complex& c) const

13

{ return a == c.a && b == c.b; } inline bool Complex::operator !=(const Complex& c) const { return !operator ==(c); } #endif // __Complex_h

10

Primeiro Projeto

Nosso primeiro projeto consiste na modelagem e implementa c ao de um vetor de n umeros complexos. De acordo com a implementa c ao a seguir, um vetor e denido pela quantidade de elementos que possui (numberOfElements), sua capacidade m axima, (capacity), um valor denominado delta, que representa o valor que ser a acrescentado a ` capacidade do vetor (redimensionamento da estrutura quando esta chegar ao seu limite m aximo) e a sequ encia de n umeros complexos em si (data). Segue abaixo a deni c ao da classe Vector, contendo a implementa ca o dos construtores, destrutor e assinatura dos m etodos. Implemente todos os m etodos declarados e n ao implementados. #define DEFAULT_V_SIZE 10 class Vector { private: int capacity; int delta; int numberOfElements; Complex* data; void resize(); public: // construtor Vector(int capacity = DEFAULT_V_SIZE, int delta = DEFAULT_V_SIZE) { this->capacity = capacity > 0 ? capacity : DEFAULT_V_SIZE;

14

this->delta = delta > 0 ? delta : DEFAULT_V_SIZE; this->numberOfElements = 0; this->data = new Complex[this->capacity]; } // construtor de c opia (profunda) Vector(const Vector& v) { this->capacity = v.capacity; this->numberOfElements = v.numberOfElements; this->delta = v.delta; this->data = new Complex[this->capacity]; for (int i=0; i<this->numberOfElements; i++) this->data[i]=v.data[i]; } // destrutor ~Vector() { delete []data; } // C opia (profunda) Vector& operator =(const Vector&); int getCapacity() const; int indexOf(const Complex&) const; bool contains(const Complex&) const; bool isEmpty() const; int size() const; void print() const; bool equals(const Vector&) const; bool operator ==(const Vector&) const; bool operator !=(const Vector&) const; void void void bool bool bool bool addHead(const Complex&); addTail(const Complex&); add(const Complex&); removeAt(int); removeLast(); removeHead(); removeValue(const Complex&);

}; // Vector

15

11

Acesso adequado ` as propriedades privadas de um Objeto

As propriedades privadas de um Objeto s ao os campos mantidos em um trecho private da classe especicada. Esse conceito e utilizado para garantir o encapsulamento e a integridade dos dados, garantindo assim que s o os m etodos da classe possam manipular tais campos. Contudo, muitas vezes precisamos que o usu ario tenha acesso de alguma forma a esses atributos. De forma geral, chamamos tais m etodos de getters e setters. Como exemplo, podemos utilizar a classe Vector modelada em sala de aula.Um objeto desta classe possui um atributo chamado numberOfElements. Esse atributo n ao pode ser alterado por m etodos ou fun co es que n ao sejam da classe Vector; eu til, contudo, que o usu ario saiba o valor possa saber o valor atributo. Sendo assim, podemos denir um m etodo p ublico que informa ao usu ario sobre esse valor, da seguinte maneira: inline int Vector::getNumberOfElements() const { return numberOfElements; }

Dependendo de decis oes de projeto, pode ser u til ter dispon vel um m etodo que permita o usu ario modicar o valor dos atributos privados delta ou capacity. Nesse caso, poder amos disponibilizar os dois seguintes m etodos: Obviamente, as implementa co es dependem das necessidades da aplica ca o. Se todos puderem ler e alterar os valores indiscriminadamente, n ao h a motivos para deixar os atributos com visibilidade privada. Pela sensibilidade do conte udo de ponteiros, uma boa pratica e sempre deix a-los com visibilidade privada. inline void Vector::setDelta(int d) { this->delta = d; } inline void Vector::setCapacity(int c) {

16

this->capacity = c; }

12

Objetos const, m etodos const e argumentos const

Ainda sem falar de orienta c ao a objetos, podemos denir algumas vari aveis como const. As op c oes s ao: char* ptr; //(1) const char* ptr; //(2) char *const ptr; //(3) const char* const ptr; //(4) Em (1) temos a declara ca o de um ponteiro para caracter. Desta forma, podemos mudar tanto o endere co armazenado na vari avel ponteiro, como seu conte udo. Os seguintes exemplos s ao v alidos: char* ptr; char c = c; ptr = &c; //correto *ptr = c; //correto Em (2) temos a declara ca o de um ponteiro para caracter de tal forma que o ponteiro pode ser alterado mas n ao o seu conte. O trecho de c odigo abaixo mostra o comportamento da palavra reservada const nesse caso: const char* ptr; char c = c; ptr = &c; //correto *ptr = c; //incorreto Em (3), o compilador permite alterar o conte udo do ponteiro, mas n ao o ponteiro. char* const ptr; //incorreto char c = c; //correto ptr = &c;

17

Em (4), a declara c ao do ponteiro foi feita de tal forma a n ao deixar a possibilidade de altera ca o do ponteiro e tampouco o seu conte udo. Isso eu till para ponteiros pr edenidos, como cadeias de caracteres. const char* const ptr = "Hello World"; char c = c; ptr = &c; //incorreto *ptr = c; //incorreto Podemos estender esse pensamento para objetos e m etodos. Alguns dos objetos utilizados em um programa podem ser modicados e outros n ao. O programador pode utilizar a palavra chave const para especicar que um objeto n ao e modic avel e que qualquer tentativa de modica-lo deve resultar em um erro de compila ca o. A instru c ap abaixo declara um objeto const chamado objectName da classe className. class className{ . . . }; const className objectName; O exemplo acima e um exemplo de instantia c ao de um objeto constante. Note que a deni c ao da classe n ao tem a declara ca o const. Nesse caso, as tentativas de modicar o objeto objectName s ao capturadas em tempo de compila c ao, ao inv es de causar erros em tempo de execu c ao. Os compiladores C++ n ao permitem chamadas de m etodos para objetos const a menos que os pr oprios m etodos tamb em sejam declarados como const. Al em disso, o compilador n ao permite que m etodos declarados const modiquem o objeto. Um m etodo e especicado como const tanto em seu prot otipo como em sua deni ca o inserindo a palavra-chave const depois da lista de par ametros do m etodo. A linha abaixo dene o m etodo methodName como const, tanto em seu prot otipo quanto na sua implementa ca o. Esse m etodo tem como retorno um dado do tipo tRret. // no arquivo .h, na classe className onde o m etodo e definido tRet methodName () const; // no arquivo .cpp onde os m etodos da classe className s~ ao implementados

18

tRet className::methodName () const { ... } Podemos ainda denir um argumento de um m etodo como const, para garantir que o argumento n ao ser a alterado dentro do m etodo. No exemplo, podemos atualizar o ponteiro para char denominado myName para apontar para o mesmo endere co recebido como argumento name, mas n ao podemos modicar o seu conte udo dentro do m etodo. void setName(const char* name) { myName = name; } Como o ponteiro e acessado somente para leitura, podemos incrementar o m etodo usando const char* const. void setName(const char* const name) { myName = name; }

A l ogica e a mesma quando aplicada a valores de retorno de m etodos.

13

Gerenciamento de mem oria utilizando operadores new e delete

Para controlar a aloca ca o e libera ca o de mem oria dinamicamente em um programa, o compilador C++ oferece dois operadores denominados new e delete. O operador new e respons avel por alocar mem oria para um objeto e o operador delete e respons avel por liberar a mem oria previamente alocada. Mostramos a seguir um exemplo de uso destes operadores. No primeiro c odigo, temos a aloca c ao de mem oria para um novo objeto chamado objectName da classe className. O operador new retorna o endere co da inst ancia criada (ponteiro para o novo objeto). Seguem abaixo alguns outros exemplos de uso do operador new para aloca ca o din amica de objetos.

19

Inicializa um double rec em-criado com 3,14159 e atribui o ponteiro resultante a ptr e, por u ltimo, destr oi o objeto apontado por ptr: double *ptr = new double(3,141159); ... delete ptr; Aloca um vetor de inteiros de 10 elementos, sem inicializa c ao, e atribui o ponteiro para esse vetor a ` vari avel array (ponteiro): int *array = new int[10]; A linha de c odigo delete array libera apenas a mem oria utilizada pelo primeiro apontado por array, mas n ao libera a mem oria previamente alocada para os demais elementos. O seguinte uso do operador delete e o mais adequado para libera ca o total da mem oria utilizada pelo objeto. delete [] array; Cria um objeto objectName da classe className: className* obj = new className(); Cria um array de objetos da classe className com 100 elementos e ap os, libera a mem oria previamente alocada. O destrutor correspondente aos objetos ser ao invocados e por m, a mem oria ocupada por eles ser a liberada. className* obj = new className[100]; ... delete [] obj;

14

Atributos de Classe - static

Os membros de uma classe podem ser static. Quando uma vari avel e declarada static dentro de uma classe, todas as inst ancias de objetos desta classe compartilham a mesma vari avel. Uma vari avel static e uma vari avel global, s o que com escopo limitado ` a classe. A declara c ao de um campo static aparece na declara ca o da classe, junto com todos os outros campos. Como a declara ca o de uma classe e normalmente inclu da em v arios m odulos de uma mesma aplica ca o via arquivos de cabe calho (arquivos .h), a declara ca o dentro da classe e equivalente a uma declara ca o de uma vari avel global extern. Ou seja, a declara ca o apenas diz que a vari avel existe, mas algum m odulo precisa deni-la. O exemplo abaixo ilustra a utiliza c ao de campos static:

20

class A { int a; static int b; // declara a vari avel, equivalente ao uso de extern para // vari aveis globais }; int A::b = 0; // define a vari avel criando o seu espa co e a inicializa void main(void) { A a1, a2; a1.a = 0; // modifica a1.b = 1; // modifica a2.a = 2; // modifica a2.b = 3; // modifica

o o o o

campo campo campo campo

a b a b

de a1 compartilhado por a1 e a2 de a1 compartilhado por a1 e a2

cout << a1.a << " " << a1.b << " " << a2.a << " " << a2.b; // imprime 0 3 2 3 } Se a deni c ao int A::b = 0 for omitida, o arquivo e compilado mas o linker acusa um erro de s mbolo n ao denido. Como uma vari avel est atica e u nica para todos os objetos da classe, n ao e necess ario um objeto para referenciar este campo. Isto pode ser feito com o operador de escopo (::). Por exemplo: A :: b = 4; Assim como atributos static comportam-se como vari aveis globais com escopo reduzido a ` classe, m etodos static s ao como fun co es globais com escopo reduzido a ` classe. Isto signica que m etodos static n ao t em o par ametro impl cito que indica o objeto sobre o qual o m etodo est a sendo executado (this), e portanto apenas os campos static podem ser acessados: class A { int a; static int b; static void f(); }; int A::b = 10; void A::f() { a = 10; // errado, a s o faz sentido com um objeto b = 10; // ok, b foi declarado static } C++ n ao suporta diretamente classes est aticas, mas se denirmos todos seus

21

m etodos e atributos com essa palavra reservada, como consequ encia teremos uma classe est atica. Como exemplo de classe est atica, podemos denir a seguinte classe para opera co es matem aticas.

class Math { private: static static public: static static };

double e = 1; double pi = 3.14; double exp(double x); //return e^x; double area(double r); //return pi*r^2;

int main() { Math m; cout << Math::exp(5) << "\n"; cout << m.exp(5) << "\n"; } Reparem que no primeiro uso do m etodo exp, nenhum objeto da classe Math foi utilizado e utilizamos o operador de escopo para informar em que classe foi denido o m etodo exp.

15

Segundo Projeto - Lista duplamente encadeada

Para exemplicar o uso dos recursos vistos at e agora, vamos iniciar a implementa c ao de uma lista duplamente encadeada, cujos n os armazenam n umeros complexos. A classe Node representa um elemento da lista e armazena um objeto Complex, al em de ponteiros para o n o anterior e o pr oximo n o da lista. class Node { public: Node() { next = prev = 0;

22

} Node(const Complex& el, tNode *ptr=0, tNode *ptr2=0): info(el) { next = ptr; prev = ptr2; } T info; tNode* next; tNode* prev; }; A classe DoubleList representa a lista duplamente encadeada propriamente dita. class DoubleList { public: DoubleList() { head = tail = 0; numberOfNodes = 0; } ~DoubleList(); int isEmpty() const { return head==0; } bool contains(const Complex& element) const { return isInList(element)!=0; } void addHead(const T&); void addTail(const T&); void deleteHead(); void deleteTail(); void deleteNode(const T&); void print() const; int size() const; private: Node* isInList(const Complex&) const; Node* head; Node* tail; int numberOfNodes; };

23

As classes acima cont em atributos e m etodos j a declarados, por em n ao implementados. Implemente os m etodos sugeridos e outros m etodos que considerem necess arios. Procure utilizar os recursos vistos at e o momento.

24

Anda mungkin juga menyukai