90
Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Embed Size (px)

Citation preview

Page 1: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classes em C++

Programação em C++

Page 2: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 2 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Abstract Data Type• Abstract Data Type - tipos de dados abstractos

definidos pelo utilizador - a simplicidade e clareza de um programa consegue-se definindo novos tipos de dados.

• Em C++ podemos definir novos tipos de dados através da definição de classes.

• Na definição duma classe, interessa ter em consideração dois factores:• Quais os modos como desejamos poder iniciar os objectos dessa classe. • Quais as operações que desejamos dispor para interactuar com objectos

da classe (quais as acções que pretendemos realizar).

Page 3: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 3 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classes em C++• O C++ associa a definição de um novo tipo de dados, à

definição de um agregado de membros (dados + funções) que toma as denominações alternativas struct ou class.

• Estruturas e classes são agregados de membros através dos quais se especificam os dados, o conjunto de operações e as funções necessárias à manipulação de objectos do tipo que esses agregados definem.

• O espaço de memória ocupado por cada objecto de um tipo definido pelo utilizador, é apenas o necessário para os dados, sendo o código dos métodos partilhado por todos os objectos desse tipo que sejam instanciados.

Page 4: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 4 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Terminologia• Classe

• Tipo de dados definido pelo programador.

• Método• Membro função de uma classe.

• Atributo• Membro dado de uma classe.

Page 5: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 5 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Terminologia• Objecto

• Instancia duma classe.

• Instanciar um objecto • Criar e iniciar um objecto de um tipo definido

pelo programador.

• Enviar uma mensagem a um objecto• Evocar o método.

• Receptor de uma mensagem • Objecto sobre o qual se evoca o método.

Page 6: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 6 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Programa exemploPrograma em C++ que, dado um ano, mostra no standard output os meses em que nesse ano ocorre sexta-feira em dia 13.

#include "Date.h”#include <iostream.h>void main(){ int year; cout<< "Qual o ano? "; cin>>year;

Date d(year, 1, 13); //Instanciar o objecto.cout <<”Ocorre sexta dia 13 em:" << endl;for( int month=1; month<=12 ; ++month ) {

d.setMonth(month);if (d.getDayOfWeek()==FRI)

cout<<' '<< d.getMonthName ();}

}

Page 7: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 7 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

AcessibilidadeDados

Métodos

Privado

Público

Os membros de uma estrutura ou classe podem declarar-se como públicos (acessíveis por todos) ou privados (acessíveis pelos seus próprios métodos), através das palavras chave public e private.

class X {private: int m; // Atributo privadopublic: int getM() { return m; }// Acesso para ler. void setM(int n) {m=n} // Acesso para escrever.};

void main() { X xa; // Instancia o objecto xa. int a, b; // Define os inteiros a e b. xa.setM(6); // Afecta xa.m com 6. a=xa.getM(); // Afecta a com xa.m. b=xa.m; // ERRO, o membro m é privado.}

•Os métodos da parte pública de uma classe constituem a interface para os objectos dessa classe.

•Os únicos membros da classe que são acessíveis do exterior, são aqueles que se situam na zona definida como pública.

•Os métodos de uma classe têm livre acesso a quaisquer membro dessa classe (públicos ou privados).

Page 8: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 8 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

• As palavras chave struct e class, são praticamente sinónimos em C++, com a excepção da acessibilidade atribuída aos seus membros, por omissão de especificador de acesso.

Acessibilidade

struct y {

int f();

private:

int k;};

equivale a

class y {

int k;public:

int f();

};

A diferença entre estas duas declarações é a acessibilidade por omissão ( private na class e public na struct).

Page 9: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 9 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Overload de nomes de métodos

Os métodos , tal como as funções globais, têm a capacidade de partilhar o mesmo nome.

class Student { char name[20]; unsigned number, note;public: void set(const char* nn,unsigned nb,unsigned nt)

{ set(nn, nb); set(nt); } void set(const char* nn, unsigned nb)

{ strncpy(name,nn,20);name[19]=0;number=nb;} void set(unsigned nt)

{ note = nt % 21; }};

Student s;s.set(“Luis Manuel”, 1024);...s.set(16);

• Pode-se a atribuir o mesmo nome a dois métodos distintos, desde que difiram entre si pelo número, ou elo tipo de parâmetros, ou pela ordem com que esses parâmetros são declarados.

• O compilador decide qual dos métodos set() é evocado, comparando o tipo dos parâmetros actuais com o tipo dos parâmetros formais de todos os métodos set().

Page 10: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 10 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtores• A instanciação de um objecto de uma dada classe, pode simultaneamente

envolver a sua iniciação com um conjunto de valores explicitados.

• O modo de iniciar um objecto, é definir como membro da classe uma função com esse propósito explícito, que toma a denominação de construtor.

• Um construtor é reconhecido por ter o mesmo nome que a classe.

class Date { ...public: Date(int , int, int); //Ano, mes e dia Date(int); // Primeiro dia do ano Date(); // Data de hoje Date(char*);// Representação em string ...};

Date today;Date firstDay(1998);Date anyDay ("2/7/1992");Date date(1992, 6, 5);

class Date { ...public: Date(int yy=0, int mm=0, int dd=0); Date(char*); // Representação string};

Date::Date(int yy, int mm, int dd) { if ( yy == 0 ) { /*data recolhida do sistema*/} else if (dd == 0) { dd= 1; } else if (mm == 0) {mm = 1; } // teste de data válida etc.}

Obtenção de vários construtores recorrendo à sobrecarga de funções.

Obtenção de vários construtores recorrendo á definição de parâmetros por omissão (default).

Page 11: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 11 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Membros ConstantesQuer os atributos quer os métodos de uma classe, podem ser declarados como constantes.Os atributos declarados como constantes, são iniciados com um valor no acto da instanciação do objecto e esse valor não pode sofrer alterações posteriores.Os métodos declarados como constantes, não podem alterar os atributos do objecto para o qual sejam evocados.

class Circle { const double pi; double radius;public: Circle(double r) : pi(3.1414159) { radius = r; } double getArea() const { return pi * radius * radius; } double getRadius() const { return radius;} void setRadius(double r) { radius = r; }};

•De uma forma geral os métodos get???() são constantes, porque retornam o valor do atributo ???. Os métodos set???() não são constantes porque tem como finalidade alterar o valor do atributo ???.•O critério sistemático de declarar como constantes os membros que pretendemos se comportem como tal, permite que o compilador detecte como erros gramaticais, lapsos que por omissão dessa declaração constituiriam erros lógicos do programa, difíceis (e morosos) de

identificar.

Page 12: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 12 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Métodos ConstantesOs métodos que não são declarados como constantes só podem ser invocados por objectos não constantes, enquanto que um método constante pode sempre ser invocado, quer os objectos sejam ou não constantes.

double Circle::getArea(const Circle &c) const { return radius *= radius * 3.1414159; // Erro}

•O compilador assinala erro gramatical, porque não é possível alterar o valor dos atributos em métodos constantes.

void f(const Circle &c) {if (c.getRadius() < 1) // Ok. c.setRadius(1); // Erro // ...

}

•O compilador assinala erro gramatical, porque se está a invocar um método não constante sobre um objecto constante.

Page 13: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 13 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Métodos inline• Os métodos de uma classe podem ser definidos inline, tal como

qualquer função global. Quando uma função (método ou função global) é definida como inline, o compilador insere o próprio código da função em todos os pontos em que for evocada .

class Count { const unsigned mod; unsigned val;public: Count(unsigned m){mod = m; val = 0; } //Métodos inline — implicitamente. unsigned get() const {return val; } void set(unsigned v) {val = v % mod;} void inc() {if (++val==mod) val=0; }};

class Count {const unsigned mod; unsigned val;

public: Count( unsigned ); //Construtor.unsigned get() const;void set( unsigned );void inc();

};

//Métodos inline — explicitamente. inline Count::Count(unsigned m) { mod = m; val = 0; }inline unsigned Count::get() const{ return val; }inline void Count::set(unsigned v){ val = v % mod; }inline void Count::inc() { if(++val==mod) val=0; }

Quando um método é definido na própria definição de classe, é implicitamente considerado inline.

Usando o prefixo inline na definição do método, é explicitamente considerado inline.

Page 14: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 14 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe Dateclass Date {public:

enum DayOfWeek { MON, TUE, WED, THU, FRI, SAT, SUN, INVALID };Date( int y, int m = 1, int d = 1 );void setYear(int y);void setMonth( int m );void setDay( int d );DayOfWeek getDayOfWeek();const char* getMonthName();const char* getDayOfWeekName();

private:unsigned year; // Anounsigned char month, day;// Mes e dia do mês// Atributos auxiliares// Número de dias desde 1 de Janeiro.int daysOfYear;

// Dia da semana de 1 de Janeiro DayOfWeek dayOfWeekYear; // Métodos auxiliaresBool leapYear( int y ) const; // Ano bissextoint getDaysOfYear();DayOfWeek getDayOfWeekYear();

};

Page 15: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 15 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

inline Date::Date( int y, int m = 1, int d = 1 ) {setYear(y); setMonth(m); setDay(d);

}

inline Bool Date:: leapYear( int y ) const { return !(y % 400) || !(y%4) && (y%100);

}

inline void Date::setYear(int y) { year=y; dayOfWeekYear=INVALID; daysOfYear=-1;

}

inline void Date::setMonth( int m ) { month=m; daysOfYear=-1;

}

inline void Date:: setDay( int d ) {if (daysOfYear!=-1) daysOfYear+=d-day; day=d;

}

Classe Date (definição dos métodos inline)

Page 16: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 16 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe Date (definição dos métodos)

// Devolve o nome do dia da semana.const char* Date::getWeakDayName() { static char *weakDayName[] = { "Segunda-feira", "Terca-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sabado", "Domingo" }; return weakDayName[ getWeakDay() ];}

// Devolve o nome do dia do mês.const char* Date::getMonthName() { static char *monthName[] = { "Janeiro", "Fevereiro", "Marco", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro","Outubro", "Novembro", "Dezembro" }; return monthName[month-1]; }

Page 17: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 17 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe Date - método getWeekYearDay()

Toma-se como referência a segunda feira de 1/1/1. Tem-se em consideração que o dia de ano novo num ano não bissexto avança um dia (365%7=1) e nos anos bissextos avança dois dias (366%7=2)

const int DAYS_OF_ONE_WEAK = 7;

WeakDay Date::getYearWeakDay () { unsigned int d = MONDAY;

for (int y=1 ; y<year ; ++y ) d += leapYear(y)?2:1;

return WeakDay ( d % DAYS_OF_ONE_WEAK );}

Page 18: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 18 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe Date - método getYearDay()

int Date::getYearDay() { const int JAN = 31, FEV = 28, MAR = 31, APR = 30, MAY = 31, JUN = 30, JUL = 31, AGO = 31, SEP = 30, OCT = 31, NOV = 30, DEC = 31;static int daysTillMonth[13] = { // Dias até.

0, JAN, JAN+FEV, JAN+FEV+MAR, JAN+FEV+MAR+APR,JAN+FEV+MAR+APR+MAY, JAN+FEV+MAR+APR+MAY+JUN, JAN+FEV+MAR+APR+MAY+JUN+JUL, JAN+FEV+MAR+APR+MAY+JUN+JUL+AGO, JAN+FEV+MAR+APR+MAY+JUN+JUL+AGO+SEP, JAN+FEV+MAR+APR+MAY+JUN+JUL+AGO+SEP+OCT, JAN+FEV+MAR+APR+MAY+JUN+JUL+AGO+SEP+OCT+NOV

}; return day –1 + daysTillMonth[month-1] + (month > 2 && leapYear(year));

}

Page 19: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 19 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe Date - método getWeekDay()

Calcula o dia da semana a partir do dia da semana em que começa o ano e o número de dias desde o início do ano. Actualiza o dia da semana em que começa o ano (yearWeekDay) se este não estiver actualizado (yearWeekDay == INVALID). Actualiza o número de dias do ano (yearDay) se não estiver actualizado (yearDay == -1) .

WeakDay Date::getWeakDay(){if (yearWeakDay == INVALID) yearWeakDay = getYearWeakDay(); if (yearDay == -1) yearDay = getYearDay();return WeakDay((yearWeakDay+yearDay) % DAYS_OF_ONE_WEAK);

}

Page 20: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 20 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Palavra chave this• Os métodos operam sobre os objectos para os quais sejam

chamados (ou evocados). • Um apontador para o objecto para o qual o método é invocado

(objecto receptor), constitui um argumento oculto (hidden) dessa função que pode ser explicitado referindo-o como this.

• Por exemplo, test é um objecto da classe Date e getDay é um método da classe Date, a chamada à função:

test.getDay()opera sobre o objecto test. Por outras palavras, test é o receptor da mensagem getDay(). De modo semelhante, se testPtr é um apontador para um objecto tipo Date, a chamada à função:

testPtr->getDay() // (*testPtr).getDay()

opera sobre o objecto apontado por testPtr.

Page 21: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 21 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Palavra chave this• Um apontador para o objecto para o qual o método é invocado

(objecto receptor), constitui um argumento oculto (hidden)

desse método que pode ser explicitado referindo-o como this.

• Nos métodos não constantes, de uma classe X, o apontador this é implicitamente declarado como:

//*this é um objecto do tipo X X* const this;

nos métodos constantes, para prevenir modificações do objecto receptor, como:

//*this é um objecto do tipo const Xconst X* const this;

tanto num caso como noutro é iniciado para apontar para o objecto sobre o qual esses métodos sejam invocado.

Page 22: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 22 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

• O uso do apontador this é implícito. Qualquer referência a um membro na definição dos métodos da classe, usa o apontador this explicita ou implicitamente para aceder ao objecto apropriado.

Palavra chave this

Quando pretendemos referir membros do objecto receptor (objecto sobre o qual se evocou o método) é desnecessário usar explicitamente o this.

class Count { const unsigned mod; unsigned val;public: Count(unsigned m){mod=m; val=0; } //Métodos inline — implicitamente. unsigned get() const {return val; } void set(unsigned v) {val = v%mod;} void inc() {if (++val==mod) val=0;}};

class Count { const unsigned mod; unsigned val;public: Count(unsigned m) {this->mod = m; this->val = 0; } //Métodos inline — implicitamente. unsigned get() const {return this->val; } void set(unsigned v) {this->val = v % this->mod; } void inc() {if (++this->val==this->mod)this->val=0;}};

Equivalente

Page 23: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 23 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Retornar o objecto receptorDefinição de um método da classe Date, que incrementa uma data (dia seguinte) e retorna a data depois de incrementada .

Date Date::inc() { static int monthDays[12]={31,29,31,30,31,30,31,31,30,31,30,31}; if ( yearDay != -1 ) ++ yearDay; if ( month==2 && day>=28+leapYear(year) || day >= monthDays[month-1]) {

day = 1;if (month == 12) { month = 1; yearDay = 0; if ( yearWeakDay != INVALID)

yearWeakDay = WeakDay((yearWeakDay + leapYear(year)? 2 : 1) % DAYS_OF_ONE_WEAK); ++year; } else ++month; } else ++day; return *this;//Retorna o objecto receptor.}

Page 24: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 24 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Objecto receptor como parâmetro actual Definição de um método da classe Date, que retorna o número de dias que medeiam entre duas datas .

long Date::getDays( Date other ) { if ( cmp(other) > 0 ) return subNorm(other);//this->subNorm(other) return - other.subNorm( *this );}

Objecto receptor como parâmetro actual

Page 25: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 25 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Membros estáticos• Um atributo de uma classe declarado estático, significa que

é partilhado por todos os objectos dessa classe.

• Trata-se de um atributo da classe. Dos atributos comum duma classe são feitas tantas instâncias quantos os objectos instanciados dessa classe, enquanto que dos atributos estáticos só é feita uma única instancia, independentemente do número de objectos dessa classe que se instanciem, ou mesmo que não se instancie nenhum objecto dessa classe.

• Um atributo estático comporta-se como uma variável global, salvo que não polui o espaço de nomes globais, dado que, mesmo que seja um membro público.

Page 26: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 26 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Atributos estáticosQuer os atributos quer os métodos de uma classe, podem tomar a natureza estática, antecedendo a sua declaração pela palavra chave static.

class X {public: static int countXs;//Exclusivamente declaração. X () { ++countXs; }; // ...};int X::countXs=0;// Definição e iniciação.

void main() { X arr[7]; // Constrói 7 objectos X construtor // sem parâmetros - X::countXs = 7. cout<<"Foram instanciados "<<X::countXs << " objectos da classe X." endl; }

Um atributo de uma classe declarado estático, significa que é partilhado por todos os objectos dessa classe.

O atributo estático countXs é incrementado de 1 por cada objecto X instanciado.

Realça-se o facto de se tornar necessário definir fora da definição da classe, e eventualmente iniciar, os atributos declarados como estáticos.

Um atributo estático, quando invocado fora da classe é qualificado pelo nome da

classe. Quando este programa for executado será escrita a mensagem:

“Foram instanciados 7 objectos da classe X”.

Page 27: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 27 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Métodos estáticosOs métodos estáticos de uma classe, comportam-se como funções globais, salvo que não poluem o espaço de nomes.

class X { static int countXs;//Atributo privado. public: X () { ++countXs; }; static int getCount() // Método público. { return countXs; } // ...};int X::countXs=0;//Definição e iniciação

void main() { X arr[7];// Constrói 7 objectos X com construtor

// sem parâmetros countObjects = 7. cout << X::getCount() << endl; }

Ao declarar uma função como método estático de uma classe em lugar de a declarar como função global, além de não se poluir o espaço dos nomes pode-se controlar o seu acesso ou o acesso aos atributos estáticos da classe.

Apesar de tolerarem ser invocados com a sintaxe dos métodos comuns, os métodos estáticos não atendem para qual dos objectos da sua classe são evocados, não sendo sequer necessário haver algum objecto instanciado dessa classe para que possam ser evocados.

Como os métodos estáticos não têm objecto receptor, o argumento oculto this não existe.

Page 28: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 28 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtor sem parâmetros• Um construtor evocado sem parâmetro é referido

como construtor default (por omissão). A razão deste facto prende-se com os seguintes factos:

Caso não se defina nenhum construtor para a classe, é implicitamente definido um construtor com corpo vazio na parte publica. Ao instanciar um objecto sem indicar uma lista de parâmetros, é reservado reserva espaço para os seus atributos, sem no entanto lhes atribuir valores.

• Se se definir, pelo menos, um construtor com parâmetros, não é implicitamente definido o construtor sem parâmetros, pelo que só se pode instanciar objectos com os construtores explicitamente definidos.

Page 29: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 29 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Arrays de Objectos• Sempre que se pretenda definir um array de objectos, é imprescindível a

existência de construtor sem parâmetros (implícito ou explícito), o que implica que, ou não se defina nenhum construtor com parâmetros, ou que se defina explicitamente um construtor sem parâmetros.

class Date { ...public: Date(int yy=0, int mm=0, int dd=0); ...};

Date dates[10];//Os 10 objectos são //iniciados por omissão //com (0,0,0).

class Date { ...public: Date(int yy, int mm=0, int dd=0); ...};

Date dates[10]; //ERRO, não existe //construtor por omissão.

Instanciar um array de 10 objectos do tipo Date, cada um iniciado com o construtor sem parâmetros, por omissão (0, 0, 0).

Não é licito a instanciação do array porque o construtor declarado requer pelo menos um argumento.

Page 30: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 30 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtor - como conversor de tipo• Um construtor com um único argumento, especifica uma

conversão do tipo do argumento para o tipo da sua classe. Tais conversões são usadas implicitamente para coerção automática.

Tendo em conta a definição:class X { ... X(int); }; void f (X arg) { ... }

São possíveis as instrução:

X a = 1; // X a(1)a = 2; // a = X(2) f(3); // f(X(3))X g() { ...return 1; }

class X { ... X(int); ... }

class Y { ... Y(X); ... };

Y a = 1; // Ilegal: Y(X(1)) // não foi tentado.

As conversões implícitas podem ser usadas em afectações, iniciadores, argumentos de funções e valores retornados por funções.

Se nenhum construtor para a classe X aceita o tipo atribuído, não é esboçada nenhuma tentativa de coerção para compatibilização de tipos, e o compilador assinala erro.

Page 31: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 31 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

DestrutorEm função das acções executadas pelo construtor, pode tornar-se necessário declarar um destrutor por forma a complementar as suas acções.

/*A classe CharPtr, que tem como finalidade despreocupar o programador quanto à libertação da memória reservada para um array de caracteres através do operador new.*/

class CharPtr {char *ptr; // Atributo dinâmico.

public: // Construtor. CharPtr(int len){ ptr = new char[len]; } // Destrutor. ~CharPtr() { delete [] ptr; } // Apontador. char *getPtr() { return ptr; }};

•A assinatura de um destrutor para uma classe X será ~X() (complemento de construtor). O destrutor não tem parâmetros nem tipo de retorno porque é invocado implicitamente.•Normalmente, as acções do destrutor são complementares às do construtor. Assim, no caso do construtor reservar espaço em memória livre através do operador new, o destrutor deve providenciar a devolução desse espaço, através do operador delete.•Quando um objecto é destruído e caso esteja definido na classe desse objecto um método destrutor, este será posto em execução automaticamente.

Page 32: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 32 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

DestrutorQuando um objecto é destruído e caso esteja definido na classe desse objecto um método destrutor, este será automaticamente posto em execução.

Um objecto é destruído:• Ao terminar o programa, se for global ou estático; Ao terminar o bloco ou a função onde foi declarado, se não for estático; Quando for destruído o objecto em que está contido; Quando o array do qual é elemento for destruído; No final da avaliação da expressão, se for um objecto temporário dela; Quando for evocado o operador delete sobre ele.

Page 33: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 33 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Destrutor ( exemplo de um espião )

O uso do método destrutor na classe Spy, permite que se espie a função factorial em cada instância da recursividade.

class Spy{ int s; public:

Spy(int ss) { cout << "Inicio - " << (s = ss) << endl;}~Spy() { cout << "Fim - " << s << endl; }

};

int factorial(int n) {Spy s(n);return (n > 1) ? n * factorial(n-1) : 1 ;

}

Page 34: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 34 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Exemplo de utilização do destrutorPodem também utilizar-se construtores e destrutores para criar segmentos de programa que sejam executados antes e depois da execução da função main(). Com efeito, os objectos que são definidos como globais, são instanciados antes da execução de main(), e só desaparecem quando o programa termina.

#include <iostream.h>

class Message {public: Message() { cout << "Inicio do programa." << endl;} ~Message(){ cout << "Fim do programa." << endl; }};

Message msg; // Instanciação do objecto msg.void main() { cout << "MAIN ... " << endl; }

Page 35: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Alojamento na memória livre

Programação em C++

Page 36: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 36 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Alojamento de dados• A linguagem C++ utiliza a memória principal de três

modos diferentes: Modo estático – Os objectos alojados neste modo persistem até

terminar o programa, mantendo sempre o mesmo endereço. São alojadas deste modo os atributos estáticos das classes, os objectos globais, e os objectos declarados como estáticos no corpo das funções.

Modo automático – Os objectos alojados neste modo são automaticamente criados e destruídos. Tomam este modo de alojamento os parâmetros actuais das funções e os objectos locais não estáticos são alojadas deste modo.

Alojamento livre – Neste modo de alojamento o espaço de memória é explicitamente requerido e explicitamente devolvido.

Page 37: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 37 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Alojamento de dados• Variáveis e objectos instanciados como estáticos,

residem na zona de dados do programa.• Variáveis e objectos instanciados como

automáticos (locais não estáticos), com tempo de vida limitado ao seu alcance, são alojados no stack.

• A região de memória livre disponível em tempo de execução de um programa, refere-se como heap ou memória livre.

Page 38: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 38 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Alojamento na memória livre• Os objectos criados em tempo de execução,

diremos que são criados dinamicamente. Quando se instancia objectos em tempo de execução, é reservado espaço para o seu alojamento e iniciado esse espaço com os valores passados como parâmetros ao construtor.

• A memória livre aceita reservas de memória para objectos alojados dinamicamente através do operador new, e desalojados através do operador delete.

Page 39: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 39 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador new• O operador new reconhece a classe do objecto e chama

automaticamente o construtor dessa classe para iniciar o bloco de memória que vai alojar. Retorna um apontador para o objecto instanciado, ou um apontador NULL se houve insucesso.

• Quando se pretende instanciar um elemento isolado, a sintaxe abreviada deste operador é a seguinte:• new type_name(<list_of_parameters>)

• Caso se pretenda instanciar dinamicamente um array de elementos da classe type_name, a sintaxe será:• new type_name [number_of_elements]

como em qualquer array, cada um dos elementos será iniciado com o construtor sem parâmetros ou o ou o construtor em que todos os parâmetros possam ser omitidos.

Page 40: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 40 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador new• O operador new instancia um objecto da classe type_name alojando sizeof(type_name) bytes na memória livre (heap), e chama o construtor em correspondência com o número de parâmetros explícitos, assegurando assim a adequada iniciação do objecto. O alojamento do objecto persiste até que o operador delete promova o seu desalojamento (destruição) ou até ao fim do programa, altura em que toda a memória livre é libertada de uma só vez.

• Por exemplo a instrução:

Date *datePtr = new Date(1998, 10, 15); reserva espaço e inicia a data em 15 de Outubro de 1998.

Page 41: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 41 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador delete• O operador delete, desaloja da memória objectos

instanciados através do operador new. Devolve à memória livre o bloco de memória ocupado pelo objecto, após realizar todas as acções que estejam explicitadas no corpo do destrutor do objecto desalojado. O operador delete é invocado com o nome do apontador para o objecto a desalojar.

delete pointer;

• No caso de se pretender desalojar um array de objectos, intercala-se entre o operador delete e o seu

operando apontador a notação []. delete [] pointer;

Page 42: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 42 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador delete• Resultam erros imprevisíveis da aplicação

do operador delete sobre um apontador que não corresponda a uma acção de new, ou da aplicação repetida do operador delete sobre o mesmo apontador.

• É indefinida a acção do operador delete se for omitida a notação [] em arrays.

• É licito, a aplicação do operador delete sobre um apontador de valor NULL.

Page 43: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 43 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operadores new e delete• Relativamente à actuação dos operadores new e delete, devemos reter que: O operador new não se limita a reservar espaço

para um objecto residir, mas providencia também a sua iniciação, conforme a definição de um construtor explícito desse objecto.

O operador delete quando invocado sobre o apontador para um objecto alojado dinamicamente, não se limita a devolver o espaço de memória do objecto a destruir. Põe previamente em execução a função destrutor definida para a classe desse objecto.

Page 44: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 44 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe CharPtrA classe CharPtr, tem como finalidade despreocupar o programador quanto à libertação da memória reservada para um array de caracteres através do operador new.

class CharPtr {char *ptr; // Atributo dinâmico.

public: // Construtor CharPtr(int len) { ptr= new char[len];} // Destrutor. ~CharPtr() { delete [] ptr; } // Apontador. char *getPtr() { return ptr; }};

.

Page 45: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 45 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Contentores• Uma larga variedade de objectos são por natureza

dinâmicos, isto é, são susceptíveis de variar o espaço reservado para os seus dados ao longo da sua existência.

• As classes contentoras de objectos ( Strings, Tabelas, Filas de Espera, Listas, etc.) destinadas a conter objectos de outras classes, e cujo montante é impossível de prever no momento da sua definição, pelo que o espaço para eles reservado terá de ser ajustado ao longo do programa.

• Declarar um membro apontador numa classe, revela normalmente a natureza dinâmica das instâncias da classe.

Page 46: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 46 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Atributos com alojamento dinâmico

• Diremos que um objecto tem natureza dinâmica se algum dos seus atributos for apontador para estruturas residentes na memória livre (criadas através do operador new).

• Diremos que um objecto foi alojado dinamicamente se a sua instanciação for efectuada através do operador new, isto é, resida na memória livre e a sua destruição seja em run-time (tempo de execução) explicitamente determinada em programa através do operador delete.

Page 47: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 47 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe Stringclass String { char *str; int cap;// Dimensão do espaço reservado para a cadeia. int len;// Numero de caracteres válidos da cadeia.public:

String(const char *s=NULL, int len=-1); ~String(); int lenght() const;int capacity() const;const char *str_c() const;void assign(const char *, int len=-1);

void assign(const String &);const char at(unsigned index) const;void at(unsigned index, char c);

};

Page 48: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 48 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

inline String::String( const char *s, int length= -1 ) {str = NULL; len = cap= 0; assign(s, length);

}

inline int String:: length() const { return len; }

inline int String::capacity() const { return cap-1; }

inline const char * String::str_c() const{ return str; }

inline char String::at( unsigned index ) const{ assert(index < length()); return str[index];}

inline void String::at( unsigned index, char c){ assert(index < length()); str[index]=c;}

inline void String:: assign(const String &s) { assign(s.str, s.len); }

Classe String (definição dos métodos inline)

Page 49: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 49 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe String - método assign()

Se o espaço em memória livre que o objecto disponha não for suficiente para conter a cadeia de caracteres que se lhe pretende afectar, será necessário:• reservar um novo espaço com dimensão suficiente;• devolver ao espaço livre a memória onde residia a cadeia anterior

// Afecta String com l caracteres da cadeia st.void String::assign(const char *st, int l) { if(l==-1) l = strlen(st); if (l+1>cap) { // Se espaço insuficiente. delete[] str; // Sem efeito se s=NULL. str=new char[sz=l+1];// Reserva novo espaço. } strncpy(str,st,len = l);// Copia os caracteres. str[len]=0; // Terminador da string.}

Page 50: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 50 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador afectaçãoSe não for definido explicitamente um operador de afectação, o compilador usa o operador afectação por omissão que se limita a copiar membro a membro.

A função f() construiu dois objectos String, ao executar a afectação s1=s2 (s1.str é afectado com s2.str), a string "Blablabla" fica perdida algures na memória livre, e os objectos s1 e s2 ficam ambos a apontar para o mesmo endereço da memória livre (s2.str), onde reside a string "Blublu”.Ao terminar a execução de f(), é evocado automaticamente o destrutor para s1 e para s2, a operação delete será executada duas vezes sobre um mesmo apontador e não será feito delete do bloco de memória onde continuará a residir a string "Blablabla". Enfim, uma barafunda.

void f() {

String s1("Blablabla" ), s2("Blublu”); s1 = s2; // Afectação não definida, copia membro a membro.}

Page 51: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 51 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operador AfectaçãoConsideremos a class String:

class String { char *str; int len; public: String(int l) {str=new char[(len=l)+1]; } ~String( ) { delete [] str; }};

void f() { String s1(10), s2(15); s1 = s2;}

A afectação de s1 por s2, coloca s1.str e s2.str a apontar para a mesma “string”. No final da função seriam feitos 2 deletes sobre o mesmo apontador e não seria feito delete sobre o apontado inicialmente por s1.str.

SoluçãoDefinição do operador afectação (=)para String

class String { … public: String(int l) { str = new char[(len=l)+1]; } ~String( ) { delete[] str; } String &operator=(const String &); };

Page 52: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 52 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtor por cópiaSe não for definido explicitamente um construtor por cópia, o compilador gera por omissão um construtor por cópia que inicia o objecto com a cópia membro a membro.

Se não se providenciar a adequada definição do construtor por cópia, é criado um objecto s2 iniciado com o seu apontador s2.str a apontar para a string de caracteres pertencente a s1 (s1.str). Advinha-se as consequências do facto… Quando terminar a execução de f(), e for invocado (automaticamente) o destrutor para s1 e s2, será executada a operação delete duas vezes sobre um mesmo apontador. Enfim, nova barafunda.

void f() { String s1(“Blabla”); String s2=s1; // Equivalente a String s2(s1). // Iniciação membro a membro de s2 com s1.}

Page 53: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 53 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtor por cópiaConsideremos a class String:

class String { char *str; int len; public: String(int l) { str=new char[(len=l)+1]; } ~String( ) { delete[] str; }};

void f() { String s1(10); String s2 = s1;}

A iniciação de s1 por s2, coloca s1.str e s2.str a apontar para a mesma “string”. No final da função seriam feitos 2 deletes sobre o mesmo apontador .

SoluçãoDefinição do construtor por cópia paraString

class String { … public: String(int l) { str = new char[(len=l)+1]; } String(const String &); ~String( ) { delete[] str; } String &operator=(const String &); };

Page 54: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 54 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe Stringclass String { char *str; int cap;// Dimensão do espaço reservado para a cadeia. int len;// Numero de caracteres válidos da cadeia.public:

String(const char *s=NULL, int len=-1); String(const String&);~String(); int lenght() const;int capacity() const;const char *str_c() const;const char at(int index) const;void assign(const char *s, int lenght=-1);void at(int index, char c);String &operator=(const String&);

};

Page 55: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 55 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Operações de afectação e iniciação•Quando se pretenda definir uma classe com atributos dinâmicos sem a pretensão de invocar em programa o construtor por cópia e o operador afectação, recomenda-se (para salvaguarda dos incautos) que estes métodos sejam definidos como privados, para impedir que sejam invocados os métodos default. •Desta forma a invocação inadvertida destes métodos acusará na compilação erro gramatical, evitando erros lógicos mais morosos de resolver.

.

Page 56: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 56 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe CharPtrclass CharPtr { int *ptr; // Atributo dinâmico. // Inviabilizar a construção por cópia // e a afectação. CharPtr(const CharPtr&) {} void operator=(const CharPtr&) {}public: // Construtor CharPtr(int len) { ptr= new char[len];} // Destrutor. ~CharPtr() { delete [] ptr; } // Apontador. char *getPtr() { return ptr; }};

.

Page 57: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 57 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe String (método at())

class String { char *str; // Cadeia de caracteres. unsigned cap;// Dimensão do espaço reservado. unsigned len;// Número de caracteres válidos. void assign(const char *s=NULL, int len=-1);public: String(const char *s=NULL, int len=-1); String(const String &); //Construtor por cópia ~String(); int lenght() const; const char *str_c() const; String &operator=(const char *s); char &at(unsigned index); char at const(unsigned index);};

Page 58: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 58 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método char &at(unsigned)

Dado que o método retorna uma referência para carácter, tanto pode ser invocado no lado esquerdo de uma afectação (para escrita), como do lado direito (para leitura).

Os métodos at, distinguem-se pela natureza const de um deles que será o único que pode ser invocado sobre objectos String declarados como constantes. O outro método, será posta em execução quando invocada por um objecto não constante.

.

Page 59: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Contentores

Programação em C++

Page 60: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 60 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Contentores • De entre os tipos de dados que numa dada

aplicação importa que o utilizador defina e utilize no programa, emerge com destaque uma família numerosa referida como classes contentores.

• Referem-se por contentores, as classes destinadas a conter objectos de um qualquer tipo, disponibilizando ao utilizador métodos cómodos de acesso (inserção, remoção, pesquisa ou ordenação) aos objectos contidos.

Page 61: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 61 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Contentores • Conforme os métodos disponíveis na sua interface, os

contentores tomam diferentes denominações:• Stack (pilha)

• Queue (fila de Espera)

• Deque (double-ended queue)

• Bag (saco),

• Set (conjunto),

• Vector, etc.

• Cada contentor é caracterizado pelo conjunto de métodos que põe disponíveis e pela estrutura de dados em que se suporte.

Page 62: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 62 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Contentores • Aos contentores exige-se fundamentalmente um bom

desempenho frente à especificidade das aplicações que os utilizam. Compreende-se por isso as múltiplas variantes de contentores que fazem parte de uma biblioteca, com estruturas de dados de suporte alternativos.

• Deve-se escolher a variante de implementação do contentor que mais se adequar às exigências da aplicação, tendo em conta:• os métodos de acesso predominantes;• a dimensão média que se preveja que o contentor tome;• as limitações de memória de dados da plataforma

hardware em que se instale.

Page 63: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 63 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe contentora - Stack• O termo stack (empilhamento) refere de um modo genérico

o armazenamento de objectos em coluna (pilha) tal que o primeiro a ser inserido seja o último a ser removido. A arrumação de pratos em pilha, é paradigmático deste contentor.

• O acesso à pilha, quer para inserir quer para remover, é feito exclusivamente pelo topo.

• A classe contentora que implementa o stack, é caracterizada por disponibilizar os métodos públicos push() para inserir um objecto no topo do stack e pop() para extrair um objecto do topo do stack.

pushpop

Page 64: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 64 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe CharStackclass CharStack{ int size; char * top, *buffer; //Inviabilizar construção por cópia e a afectação. CharStack (const CharStack&){}//Construção por cópia. void operator=(const CharStack &){} //Afectaçãopublic: CharStack(int sz){ top=buffer=new char[size=sz]; } ~CharStack () { delete [] buffer; } void push(char c){ assert(!full()); *top++ = c;} char pop() { assert(!empty()); return *--top; } bool full()const { return top-buffer==size; } int empty() const { return top == buffer; }};

Page 65: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 65 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Classe contentora - CharStack• Além dos métodos públicos push() e pop(), dispõe dos

métodos:• empty() - testa se o stack não contem objectos;• full() - testa se já não dispõe de espaço para armazenar

mais objectos;

• Construtor - reserva na memória livre (heap) um bloco de memória para o array de objectos;

• Destrutor - providencia a devolução à memória livre do espaço reservado;

• e dos métodos privados construtor por cópia e operator =() - inviabilizam a cópia e a afectação.

Page 66: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 66 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição das classes CharStack e IntStack

class CharStack{ int size; char * top, *buffer;public: CharStack(int sz){ top=buffer=new char[size=sz]; } ~CharStack () { delete [] buffer; } ~CharStack () { delete [] buffer; } void push(char c){ assert(!isFull()); *top++ = c;} char pop() { assert(!isempty()); return *--top; } bool full()const { return top-buffer==size; } int empty() const { return top == buffer; }};

class IntStack{ int size; int * top, *buffer;public: IntStack(int sz){ top=buffer=new int[size=sz]; } ~IntStack () { delete [] buffer; } void push(int c){ assert(!isFull()); *top++ = c;} int pop() { assert(!isempty()); return *--top; } bool full()const { return top-buffer==size; } int empty() const { return top == buffer; }};

Page 67: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 67 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe Stack

/*Por mera mudança das definições de char ou int por T, podemos redefinir o Stack para trabalhar com qualquer tipo de objectos. */typedef char T;class Stack{ int size; T * top, *buffer;public: Stack(int sz){ top=buffer=new T[size=sz]; } ~Stack () { delete [] buffer; } ~CharStack () { delete [] buffer; } void push(T c){ assert(!isFull()); *top++ = c;} T pop() { assert(!isempty()); return *--top; } bool full()const { return top-buffer==size; } int empty() const { return top == buffer; }};

Page 68: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 68 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Estrutura array ordenado A estrutura array ordenado, quanto a desempenho, apresenta

as seguintes características, no que se refere à: Pesquisa de um elemento, o array tem um excelente

desempenho, se adoptarmos pesquisa dicotómica - desempenho da ordem de (log n) sendo n o número de elementos a ordenar;

Remoção de um elemento, é altamente penalizante, dado que implica deslocar elementos. Se o elemento a remover se situar no início do array e o array contiver n elementos, implica executar n transferências de elementos;

Inserção de um elemento, ainda se pode tornar-se mais gravoso, na medida em que, além de ter de abrir espaço, se o array já não comportar mais nenhum elemento é necessário criar novo espaço mais dilatado.

Page 69: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 69 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Estrutura Lista• Uma alternativa será adoptar uma estrutura lista

ligada, que permita um melhor desempenho das inserções e remoções, mesmo que penalizando, relativamente aos arrays, as acções de pesquisa.

• Quanto a desempenho insuportável, tanto pode acontecer com os arrays como com as listas e a opção entre um e outro destes contentores terá de ser feita, frente aos métodos de acesso que uma dada aplicação tenha como mais frequentes, o número de objectos, etc.

Page 70: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 70 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Estrutura Lista• Uma lista ligada, pode referir-se como um contentor de

objectos na qual podemos inserir ou remover um objecto em qualquer posição.

• Cada objecto da lista aponta para outro (ou outros) objectos da lista, dizendo-se por isso que os objectos estão ligados ou encadeados entre si.

• Os elementos de uma lista, para os quais não se disponha de apontadores fixos específicos, só podem ser acedidos sequencialmente. Daí o gravoso desempenho das acções de pesquisa relativamente aos arrays, os quais aceitam pesquisa dicotómica.

• A principal virtude das listas reside na facilidade (rapidez) com que permitem a execução de acções de inserção e remoção.

Page 71: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 71 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Exemplo de uma lista ordenada de inteiros

• O critério para organizar uma lista simplesmente ligada é ligar todos os nós, colocando cada nó a apontar para o nó seguinte.

• Os objectos nós além de conterem o inteiro a inserir, explicitam o nó seguinte, isto é, têm dois atributos: um data que contem os dados a armazenar e um ptNext que aponta para o node seu sucessor na lista, ou toma o valor NULL quando não haja sucessor.

7 10 NULL4

Page 72: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 72 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe IntList

class IntList { struct IntNode { // Definição da classe IntNode

int data;IntNode* ptNext;IntNode(int n) { data=n;}

};IntNode* ptList; // Apontador para o 1o nó

...public:

IntList() { ptList=NULL; } // Inicia a lista~IntList(); // Destroi todos os nodesbool insert(int n); // Inserir ordenadobool remove( int n); // Removerbool contain(int n)const;//Testa se n existebool empty() const; //Testa lista vaziavoid print() const;

};

data ptNext

Page 73: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 73 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método para inserir ordenadamente

??ptList

NULLprev next

v

? ?nextprev

va) b)

• Este método percorre sequencialmente a lista com dois apontadores prev e next iniciando prev a NULL e next com ptList (cabeça da lista). Quando a iteração termina distingue duas condições: • (a) A lista está vazia ou o inteiro v a inserir é menor que o

associado ao IntNode na cabeça da lista (prev == NULL).

• (b) Caso contrário (prev != NULL) insere o novo nó como sucessor do nó apontado por prev.

Page 74: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 74 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método para inserir ordenadamentebool IntList:: insert( int val ) { IntNode *prev, *next; if( find(val, prev, next) )

return false; // Reserva memória para o novo nó. IntNode * ins= new IntNode(val); //Ligar o novo IntNode. if ( prev != NULL )

prev->ptNext= ins;//Ligar o anterior ao novo. else ptList = ins; //Ligar a cabeça ao novo. ins->ptNext= next;//Ligar o novo ao seguinte. return true;}

Page 75: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 75 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método find()

bool IntList::find(int val, IntNode*& prev, IntNode*& next) const{ for ( next = ptList, prev = NULL;

next && next->data < val; prev = next, next= next->ptNext);

return next && next->data == val;}

7 10 NULL4ptList

pt

Page 76: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 76 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método para remover ordenadamente• Percorre sequencialmente a lista com dois apontadores prev

e curr iniciando prev a NULL e curr com ptList (cabeça da lista). Quando a iteração termina distingue duas condições:

• Caso o nó a remover seja o primeiro da lista (prev == NULL, o nó será removido actualizando o apontador ptList;

• Caso contrário (prev != NULL), actualiza-se o sucessor do nó apontado por prev.

7 10 NULL4ptList

nextprev

Page 77: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 77 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método para remover ordenadamente

bool IntList:: remove(int val) {IntNode *prev, *next;if( !find(val, prev, next) )

return false;if ( prev )

// Desliga do anterior.prev->ptNext =next->ptNext;

else // Desliga da cabeça.ptList = next->ptNext;

// Liberta a memória. delete next;return true;

}

Page 78: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 78 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Métodos contain(), print()e destrutor

bool IntList:: contain( int val ) const { for( IntNode *pt=ptList;//Apontar para o inicio.

pt && pt->data < val; pt=pt->ptNext); //Avançar para o próximo.

return pt && pt->data == val;}

void IntList::print() const { for( IntNode* pt =ptList; pt; pt = pt->ptNext)

cout << pt->data << ' '; cout << endl;}

IntList::~IntList() { while(!empty()) { IntNode *aux=ptList; ptList= ptList->ptNext; delete aux; }}

Page 79: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 79 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Lista com sentinela.

• Permite a simplificação dos algoritmos dos métodos de inserção e remoção, dado que deixa de ser necessário considerar separadamente o caso da inserção e remoção á cabeça.

7 104?sentinela

• O atributo da lista é um nó auxiliar (guard), iniciado em anel.

?sentinela

Page 80: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 80 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe IntList com sentinela

class IntList { struct IntNode { int data; IntNode* ptNext; IntNode(int n, IntNode *n) { data=n; ptNext = n;} IntNode() {data=0;ptNext=this;} //Construir guard. }; IntNode guard;//Auxiliar para simplificar os métodos. ...public:

~IntList(); // Destroi todos os nodesbool insert(int val); // Inserir ordenadobool remove( int val); // Removerbool contain(int val)const;//Testa se val existebool empty() const; //Testa lista vaziavoid print() const;

};

Page 81: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 81 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método insert()

bool IntList::insert( int val ) {IntNode *prev, *next;if( find(val, prev, next) )

return false;prev->ptNext= new IntNode(val, next);return true;

}

/*Na lista sem nó guard { IntNode *prev, *next; if(find(val,prev,next))return false; IntNode * ins= new IntNode(val); //Criar o novo nó. if ( prev!=NULL ) prev->ptNext= ins;//Ligar-se ao anterior else ptList = ins; //ou à cabeça. ins->ptNext= next; //Ligar-se ao seguinte. return true;} */

Page 82: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 82 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método find()

bool IntList::find( int val, IntNode*& prev, IntNode*& next ) const { for (guard.data= val, next=guard.ptNext, prev=&guard;

next->data < val; prev = next, next = next->ptNext);

return next != &guard && next->data == val;}

/*Na lista sem nó guard { for ( next = ptList, prev = NULL;

next && next->data < val; prev = next, next= next->ptNext);

return next != NULL && next->data == val;} */

Page 83: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 83 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método remove()

bool IntList:: remove(int val) {IntNode *prev, *next;if(!find(val, prev, next))

return false;prev->ptNext = next->ptNext; // Desligar.delete next; // Libertar a memória.return true;

}

/*Na lista sem nó guard { IntNode *prev, *next; if(!find(val,prev,next))return false; if (prev) prev->ptNext=next->ptNext;//Desliga do anterior. else ptList = next->ptNext; //Desliga da cabeça. delete next; //Liberta a memória. return true;} */

Page 84: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 84 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Lista duplamente ligada.

sentinela?

Mantém-se o critério de utilizar como atributo da IntDList umIntDNode auxiliar (guard) com fecho em anel .

Permite:• Simplificar ainda mais os algoritmos de inserção e remoção;• Acesso sequencial nos dois sentidos.

O critério para organizar uma lista duplamente ligada é ligartodos os nós, colocando cada nó a apontar para o nó seguinte e para o nó anterior.

10sentinela

74?

Page 85: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 85 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Definição da classe IntDList

class IntDList { struct IntDNode {

int data;IntDNode* ptNext, *ptPrev;IntDNode( int n, IntDNode *next);IntDNode();~IntDNode();

}; IntDNode guard;//Auxiliar para simplificar. ...public:

~IntDList(); // Destroi todos os nodesbool insert(int n); // Inserir ordenadobool remove( int n); // Removerbool contain(int n)const;//Testa se n existebool empty() const; //Testa lista vaziavoid print() const;

};

Page 86: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 86 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Construtores do IndDNode

// Iniciaçãoinline IntDNode::IntDNode() {

ptNext = ptPrev = this; }

// Inserção de um node na listainline IntDNode::IntDNode(int val,IntDNode*next){ data = val; ptNext = next; ptPrev = next->ptPrev; ptNext->ptPrev = ptPrev->ptNext = this;}

??

next

valthis

sentinela?

Page 87: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 87 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Destrutor do IndDNode (remoção).

7 10 NULL4ptList

pt

// O nó desliga-se da lista.IntDNode::~IntDNode() {

ptPrev->ptNext = ptNext;ptNext->ptPrev = ptPrev;

}

Page 88: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 88 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método insert()

bool IntDList:: insert(int val) {IntDNode *next;if ( find(val, next) )

return false;new IntDNode(val, next);return true;

}/* Simplesmente ligadabool IntList::insert(int val){

IntNode *prev, *next;if( find(val, prev, next) ) return false;prev->ptNext= new IntNode(val, next);return true;

}*/

Page 89: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 89 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método remove()

bool IntDList:: remove(int val) {IntDNode *next;if(!find(val, next))

return false;delete next;return true;

}

/* Simplesmente ligadabool IntList:: remove(int val) { IntNode *prev, *next; if(!find(val, prev, next)) return false; prev->ptNext = next->ptNext; delete next; return true;} */

Page 90: Programação em C++ Pimenta Rodrigues Pedro Pereira Manuela Sousa Classes em C++ Programação em C++

Classes em C++ 5 - 90 Programação em C++Pimenta RodriguesPedro PereiraManuela Sousa

Método find()

bool IntDList::find(int val,IntDNode *&next){for (guard.data = val, next=guard.ptNext; next->data < val;

next=next->ptNext);return next!=&guard && next->data==val;

}

/*Na lista simplesmentebool IntList::find(int val, IntNode*& prev,IntNode*& next)const{ for (guard.data= val, next=guard.ptNext, prev=&guard;

next->data < val; prev = next, next = next->ptNext);

return next != &guard && next->data == val;}*/