List templates Vamos considerar a lista ligada (singly linked list) O objecto da classe slink O objecto da classe slink O objecto da classe slink NULL.

Slides:



Advertisements
Apresentações semelhantes
LISTAS Dilvan Moreira, parcialmente baseado em material do prof. Ricardo Campello.
Advertisements

ABSTRAÇÃO processo de representar um grupo de entidades através de seus atributos comuns feita a abstração, cada entidade particular (instância) do grupo.
Métodos, Parâmetros, Argumentos e Contratos
Classes C++ Class nome da classe { private: membros privados
Recursividade Prof. Rosana Palazon.
Listas encadeadas Prof. Rosana Palazon.
Listas duplamente encadeadas
Programação II Estruturas de Dados
1. Classes 2. Membros estáticos 1.1. Palavra chave this
Struct slink { slink* next; slink() { next=0; } slink(slink* p) { next=p; } virtual void print_me() = 0; }; next função virtual pura 1º constructor 2º
Vamos abordar o exemplo
Algoritmos e Estrutura de Dados I
Polimorfismo e Acoplamento Dinâmico
Templates Traduzido de:
INF Computação Gráfica
Listas lineares Listas Lineares Fila Dupla Pilha Fila Saída restrita
Listas lineares Listas Lineares Fila Dupla Pilha Fila Saída restrita
Árvores Introdução e Aplicações Árvores de Busca Binária Fundamentos
Estruturas de Dados e Algoritmos
Listas Ligadas – Conceitos Avançados
Estruturas de Dados I Prof.: Sergio Pacheco Prof.: Sergio Pacheco 1 1.
Universidade Federal do Espírito Santo
7 Abstração Genérica Unidades genéricas e instanciação.
Listas com Ponteiros Listas encadeadas Listas circulares.
LISTAS “LINKADAS” No Mapeamento Seqüencial tem-se o problema de
Centro Integrado de Tecnologia da Informação
1 Aula 3 Listas e iteradores (cont.). 2003/2004 Programação Orientada para Objectos 2 ListaDeInt : interface class ListaDeInt { public: typedef int Item;
Aula 8 Polimorfismo.
1 Aula 7 Herança. 2003/2004 Programação Orientada para Objectos 2 Conceitos fundamentais: Herança Polimorfismo Ligação dinâmica.
2002/2003 Programação Orientada para Objectos 1 Aula 3 Utilização de listas Melhorando a implementação das listas e iteradores Reflexão sobre interfaces.
Aula 2 Listas e iteradores.
Métodos Programação II
Listas Encadeadas.
exercícios listas encadeadas
Professor: Hyggo Almeida
Classes Revisando: –Forma de implementação de estruturas específicas –Atributos (grupos de dados) –Métodos (conjuntos de procedimentos)
Aula prática 13 Orientação a Objetos – C++ Parte 1
Linguagens de Programação
1 Tipos avançados (versão C/C++) Em C/C++ existe a possibilidade de criar novos tipos. Em C esta possibilidade só pode ser materializada com estruturas.
1 Ponteiros Ponteiros são variáveis que guardam localizações em memória. A declaração de uma variável ponteiro x para um dado tipo type é type *x; Essa.
Linguagem de Programação II
Prof. Ricardo Santos PONTEIROS
Tipos Abstratos de Dados
Estudo de Caso: um editor de documentos
Técnicas de Desenvolvimento de Programas
Programação orientada a objectos em C++
Educação Profissional Técnica de Nível Médio Curso Técnico de Informática Disciplina: Estrutura de Dados Professor: Cheli dos S. Mendes da Costa Listas.
2002/2003 Programação Orientada para Objectos 1 Aula 6 Classes que reservam recursos externos Problemas comuns Construtores e destrutores Construção por.
Educação Profissional Técnica de Nível Médio Curso Técnico de Informática
2002/2003 Programação Orientada para Objectos 1 Aula 2 Noção de lista e de iterador Operações com listas e iteradores Classes embutidas.
Aula Prática 4 Monitoria IP/CC (~if669).
Aula prática 3 Aprofundando em Funções Parâmetros de uma função Uso do return Execução Variáveis Global, local e estática Monitoria de Introdução à.
Estruturas de Dados I Segundo Período de 2008 Gabarito da Primeira Prova.
Aula Prática 3 Funções Monitoria Introdução à Programação.
Linguagem de programação I A Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação Versão: _01.
Copyright 1998, Departamento de Informática da UFPE. Todos os direitos reservados sob a legislação em vigor. Variáveis e métodos estáticos, Passagem de.
Algoritmos e Programação MC102 Prof. Paulo Miranda IC-UNICAMP Aula 15 Ponteiros.
JAVA – Fila ATAI.
Estruturas Homogêneas – Vetores e Matrizes
Linguaguem de Programação II
Programação Orientada a Objetos para Redes de Computadores Prof. Miguel Elias Mitre Campista POO para Redes de Computadores.
Linguagem de Programação
Estrutura de Dados Prof. André Cypriano M. Costa
Lista Ligada Estrutura de Dados II Prof. Gale. Vantagens  Crescem (ou decrescem) à medida que elementos são inseridos (ou removidos)  seqüência encadeada.
Laboratório de Computação Aula 06 e 07 – Implementação de classes Prof. Fábio Dias
1 Aula 07 Strings Prof. Filipe Mutz. 2 Em nossos programas ainda não vimos como armazenar palavras e textos, e eles são muito importantes! Exemplos: Programas.
FUNÇÕES Dilvan Moreira (baseado em material de Z. Liang)
CLASSES EM JAVA Dilvan Moreira (baseado no livro Big Java)
Introdução a Programação
Transcrição da apresentação:

List templates Vamos considerar a lista ligada (singly linked list) O objecto da classe slink O objecto da classe slink O objecto da classe slink NULL next slink() { next = 0; } slink(slink* p) { next = p; } struct slink{ slink* next; slink() { next=0; } slink(slink* p) { next=p; }};

Agora podemos definir a classe slist_base que pode conter os objectos de qualquer classe derivada de slink: class slist_base { slink* last;// last->next é a cabeça da lista public: void insert(slink* a);// incluir na cabeça da lista void append(slink* a);// incluir no final da lista slink* get();// retornar e remover a cabeça void clear(){ last = 0; } slist_base(){ last = 0; }// o primeiro construtor slist_base(slink* a) { last = a->next = a; } // o segundo construtor class bad_last {};// a classe de excepções friend class slist_base_iter;// a classe iterador };

O nome slist_base significa que a classe vai ser usada como a base para (classes de listas ligadas) singly linked list classes. Vamos considerar a implementação das funções diferentes pertencentes à classe slist_base. Elas são insert, append e get. void slist_base::insert(slink* a) {if(last) a->next = last->next; else last = a; last->next = a; }

void slist_base::insert(slink* a) {if(last) a->next = last->next; else last = a; last->next = a; } last next last->next é a cabeça da lista next a last=0 next a a=last else last = a; last->next = a;

void slist_base::insert(slink* a) {if(last) a->next = last->next; else last = a; last->next = a; } last 0 a->next = last->next; last->next = a; next a last next last next

void slist_base::insert(slink* a) {if(last) a->next = last->next; else last = a; last->next = a; } last 0 a->next = last->next; last->next = a; next a last next

O objecto da classe slink last->next last O objecto da classe slink last->next last a->next a slink incluir na cabeça da lista {if(last) a->next = last->next; else last = a; last->next = a;} void slist_base::insert(slink* a) a->next = last->next; last->next = a;

void slist_base::append(slink* a) {if(last){ a->next = last->next; last = last->next = a;} else last = a->next = a; }

void slist_base::append(slink* a) {if(last){ a->next = last->next; last = last->next = a;} else last = a->next = a; } next a last=0 next a last = a->next = a; last

void slist_base::append(slink* a) {if(last){ a->next = last->next; last = last->next = a;} else last = a->next = a; } last->next é a cabeça da lista next a { a->next = last->next; last = last->next = a;} last 0 last next last next last->next

void slist_base::insert(slink* a) last next a void slist_base::append(slink* a) next last Cabeça Final

O objecto da classe slink last->next last O objecto da classe slink last->next last a->next a slink incluir no final da lista {if(last) a->next = last->next; last = last->next = a; else last = a->next = a;} void slist_base::append(slink* a) a->next = last->next; last->next = a; last last = a;

O primeiro objecto last->next last ainsert O primeiro objecto a->next = a last appenda last=a last new incluir na cabeça new incluir no final last a a A seguinte figura mostra como as funções insert e append funcionam.

slink* slist_base::get() {if (last == 0) throw bad_last(); slink* f = last->next; if ( f == last) last = 0; else last->next = f->next; return f; }

last retornar slink* slist_base::get() { if (last == 0) throw bad_last(); slink* f = last->next; if ( f == last) // remover o // ultimo elemento last = 0; else last->next = f->next; return f; } f

Para usar a classe slist_base podemos derivar da classe slink a classe nova. Por exemplo, vamos considerar o elemento name que precisamos de incluir na lista: class name : public slink{ }; void f(const char* s) {slist_base slb; slb.insert(new name(s) ); //..... name* p = (name*)slb.get();// cast explícito //..... delete p; } Este estilo não é bom. Nós gostaríamos de fornecer a versão type-safe da classe slist_base:

template class Islist : private slist_base{ public: void insert(T* a){ slist_base::insert(a); } void append(T* a){ slist_base::append(a); } T* get(){ return (T*) slist_base::get(); } }; De notar que slist_base é uma classe base privada da classe Islist. Nós não queremos permitir ao utilizador mudar a classe slist_base. Este template pode ser usado da seguinte forma: void f(const char* s) {Islist ilst; ilst.insert(new name(s) ); //..... name* p = ilst.get(); //..... delete p; }

Neste caso o objecto pode ser incluído na Islist se este objecto for derivado da slink. Por isso, nós não podemos definir Islist, por exemplo, de inteiros. Vamos considerar uma lista que não requer esta restrição. template struct Tlink : public slink { T info; Tlink(const T& a) : info(a) { } A classe Tlink tem a cópia do objecto do tipo T e ligação fornecida através da classe base slink. Agora podemos declarar a classe Slist.

template class Slist_iter; // vamos considerar esta linha // um pouco mais à frente template class Slist : private slist_base { public: void insert(const T& a) { slist_base::insert(new Tlink (a) ); } void append(T& a) { slist_base::append(new Tlink (a) ); } T get(); friend class Slist_iter ;// vamos considerar esta linha // um pouco mais à frente }; template T Slist ::get() {Tlink * lnk = (Tlink *) slist_base::get(); T i = lnk->info; delete lnk; return i; }

O uso da classe Slist é tão fácil como o uso da classe Islist. A diferença é que é possível definir o objecto da classe Slist sem necessidade de o derivar da respectiva classe slink. Mas intrusive list, tais como Islist, têm a vantagem na eficiência em termos de execução e frequentemente em compacidade. Cada vez que o objecto for passado na Slist esta lista precisa de reservar o objecto do tipo Tlink e copiar o tipo. Como resultado duas coisas podem ser feitas. Primeiro, Tlink é um bom reservador de memória. Segundo, isto é boa ideia guardar objectos na primary list que é intrusive e usar a lista não intrusive apenas quando é necessário o membership de algumas listas. void f(name* p) {Islist lst1; Slist lst2; lst1.insert(p);// ligação através do objecto *p lst2.insert(p);// o uso do objecto separado para guardar p }

Slist é uma classe boa para pequenos objectos, tais como inteiros e ponteiros. Para grandes objectos é melhor guardar ponteiros para estes objectos na lista. Iteração A classe não fornece qualquer possibilidade para olhar para dentro da lista. Mas ela declara a classe amiga (friend) slist_base_iter. Por isso, nós podemos declarar o iterador:

class slist_base_iter{ slink* ce;// o elemento corrente slist_base* cs;// a lista corrente public: inline slist_base_iter(slist_base& s); inline slink* operator()(); }; slist_base_iter::slist_base_iter(slist_base& s) {cs = &s; ce = cs->last;} slink* slist_base_iter::operator()() // retornar 0 para indicar o final do iteração {slink* ret = ce ? (ce=ce->next) : 0; if (ce == cs->last) ce =0; return ret; } A seguinte figura explica como o construtor da classe slist_base_iter e o operador operator()() funcionam.

slist_base_iter::slist_base_iter(slist_base& s) {cs = &s; ce = cs->last;} slink* slist_base_iter::operator()() // retornar 0 para indicar o final do iteração {slink* ret = ce ? (ce=ce->next) : 0; if (ce == cs->last) ce =0; return ret; } last next CS ce

Para um dado iterador todos os iteradores para Slist e Islist podem ser construídos. Primeiro devemos declarar os iteradores como friends para as classes deles. template class Islist_iter; template class Islist : private slist_base { public: friend class Islist_iter ; }; template class Slist_iter; template class Slist : private slist_base { public: friend class Slist_iter ; }; De notar que os nomes dos iteradores foram introduzidos sem definir as suas classes template. Isto apresenta a possibilidade de usar dependências entre templates. Agora vamos definir iteradores.

template class Islist_iter : private slist_base_iter { public: Islist_iter(Islist & s) : slist_base_iter(s) { } inline T* operator()() { return (T*) slist_base_iter::operator()(); } }; template class Slist_iter : private slist_base_iter { public: Slist_iter(Slist & s) : slist_base_iter(s) { } inline T* operator()(); }; template T* Slist_iter ::operator()() {Tlink * lnk = (Tlink *) slist_base_iter::operator()(); return lnk ? &lnk->info : 0; }

De notar que mais uma vez nós usamos a derivação duma família de classes (que são os templates) da classe base única. Neste caso a herança expressa comunalidade e permite eliminar a replicação do código. Os nossos iteradores podem ser usados da seguinte forma:

void main(void) { try{ Slist lst1; lst1.insert(3); lst1.insert(4); lst1.insert(5); int p = lst1.get();cout << p << endl; p = lst1.get();cout << p << endl; lst1.insert(30); lst1.insert(40); lst1.insert(50); Slist_iter iter1(lst1); const int* ii; while( (ii=iter1() ) != 0 ) cout << (*ii) << endl; } catch(slist_base::bad_last) { cerr << "bad last\n"; exit(1); } } Os resultados:

Sumário de templates 1. Os templates são uma das capacidades do C++ para a reutilização de código. 2. Existem dois tipos de template: class template e function template. É permitido usar templates para as funções globais e para as funções locais pertencentes a qualquer classe. 3. Template permite passar um ou mais tipos dentro da classe como parâmetros. O tipo pode ser ou qualquer tipo predefinido na linguagem ou qualquer tipo novo definido pelo utilizador. 4. O argumento de function template deve definir o tipo com pelo menos um argumento na função. Isto permite garantir que a própria versão da função vai ser seleccionada com a ajuda da avaliação dos tipos dos argumentos desta função. 5. Os parâmetros de template devem ser fornecidos em símbolos tais como ( ). Alguns parâmetros dentro de ( ) podem ser também símbolos. Para evitar ambiguidade precisamos de inserir o espaço entre os símbolos respectivos. SWAP >::swap(my_array);

6. Templates permitem construir os programas que foram compostos de partes relativamente independentes. Uma parte é orientada na construção do interface e a outra - na realização de funções diferentes. Finalmente esta possibilidade dá novos meios para suportar o encapsulamento e os tipos abstractos, particularmente para separar o interface e a implementação. 7. As regras adoptadas na linguagens C/C++ para converter os tipos dos argumentos não podem ser usadas para templates. 8. Function template pode ser redefinida nas seguintes ocasiões: existem outras funções que têm o mesmo nome ou existem outras functions template que têm o mesmo nome. 9. Podemos usar as expressões constantes como argumentos de template. 10. Ao declarar os objectos de qualquer classe definidos com a ajuda de templates podemos dizer que dois objectos são objectos da mesma classe se eles tiveram o mesmo template ou todos os argumentos tiverem os mesmos valores.

11. Dois tipos construídos do mesmo template são diferentes independentemente da possibilidade das conversões automáticas adoptadas na linguagem C Os argumentos de template podem ser só expressões constantes (i.e. neste caso eles não são tipos). 13. Ao definir os argumentos de template como classes bases e derivadas nós vamos perder muitas conversões definidas na linguagem para objectos destas classes. 14. Existe uma relação entre templates e a herança. Templates permitem mostrar abstracções comuns entre tipos diferentes. A herança permite apresentar interfaces comuns para classes diferentes. 15. O uso de templates e herança dá-nos os meios para separar o interface da implementação. 16. A declaração de template só pode ser global. 17. Cada classe ou função geradas de acordo com o template têm copias únicas dos seus componentes estáticos.

Agora vamos considerar alguns exemplos struct slink template struct Tlink public class slist_base template class Slist private template class Islist private class slist_base_iter template class Islist_iter template class Slist_iter private

struct slink{ slink* next; slink() { next=0; } slink(slink* p) { next=p; }}; template struct Tlink : public slink { T info; Tlink(const T& a) : info(a) { } };

class slist_base { slink* last;// last->next é a cabeça da lista public: void insert(slink* a);// incluir na cabeça da lista void append(slink* a);// incluir no final da lista slink* get();// retornar e remover a cabeça void clear(){ last = 0; } slist_base(){ last = 0; }// o primeiro construtor slist_base(slink* a) { last = a->next = a; } // o segundo construtor class bad_last {};// a classe de excepções friend class slist_base_iter;// a classe iterador }; template class Slist : private slist_base { public: void insert(const T& a) { slist_base::insert(new Tlink (a) ); } void append(T& a) { slist_base::append(new Tlink (a) ); } T get(); friend class Slist_iter ; };

template class Islist : private slist_base{ public: void insert(T* a){ slist_base::insert(a); } void append(T* a){ slist_base::append(a); } T* get(){ return (T*) slist_base::get(); } friend class Islist_iter ; };

void slist_base::insert(slink* a) { if(last) a->next = last->next; else last = a; last->next = a; } void slist_base::append(slink* a) { if(last){ a->next = last->next; last = last->next = a;} else last = a->next = a; } slink* slist_base::get() { if (last == 0) throw bad_last(); slink* f = last->next; if ( f == last) last = 0; else last->next = f->next; return f; }

template T Slist ::get() {Tlink * lnk = (Tlink *) slist_base::get(); T i = lnk->info; delete lnk; return i; } Forward declarations: template class Slist_iter; template class Islist_iter;

class slist_base_iter{ slink* ce;// o elemento corrente slist_base* cs;// a lista corrente public: inline slist_base_iter(slist_base& s); inline slink* operator()(); }; template class Islist_iter : private slist_base_iter { public: Islist_iter(Islist & s) : slist_base_iter(s) { } inline T* operator()() { return (T*) slist_base_iter::operator()(); } }; template class Slist_iter : private slist_base_iter { public: Slist_iter(Slist & s) : slist_base_iter(s) { } inline T* operator()(); };

slist_base_iter::slist_base_iter(slist_base& s) {cs = &s; ce = cs->last;} slink* slist_base_iter::operator()() // retornar 0 para indicar o final do iteração {slink* ret = ce ? (ce=ce->next) : 0; if (ce == cs->last) ce =0; return ret; } template T* Slist_iter ::operator()() {Tlink * lnk = (Tlink *) slist_base_iter::operator()(); return lnk ? &lnk->info : 0; }

int main(int argc, char* argv[]) {slist_base sb;slink sl;sb.insert(&sl); try{ Slist lst1; lst1.insert(3); lst1.insert(4); lst1.insert(5); int p = lst1.get();cout << p << endl; p = lst1.get();cout << p << endl; lst1.insert(30); lst1.insert(40); lst1.insert(50); Slist_iter iter1(lst1); const int* ii; while( (ii=iter1() ) != 0 ) cout << (*ii) << endl; } catch(slist_base::bad_last) { cerr << "bad last\n"; exit(1); } return 0; }

size c_l template class stack {unsigned counter; int size; T* c_l; T* top; public: T pop(); void push(T&); stack(unsigned); virtual ~stack(); int get_size() { return size; } int get_counter() { return counter; } }; top counter

template stack ::stack(unsigned tamanho) {top = c_l = new T[size = tamanho]; counter=0;} template stack ::~stack() {delete [] c_l;} template void stack ::push(T &new_s) {*top++ = new_s; counter++;} template T stack ::pop() {if(counter==0) {cerr<<"stack is empty\n"; return NULL;} counter--; return *--top; }

int main(int argc, char* argv[]) {stack pilha=10; char *ss1 = "Aveiro",*ss2 ="Ilhavo"; double a = 10.15, b = 5.45; pilha.push(ss1); pilha.push(ss2); cout << pilha.get_size() << endl; cout << pilha.get_counter() << endl; cout << pilha.pop() << endl; stack pilha1(10); pilha1.push(a); pilha1.push(b); cout << pilha1.pop() << endl; return 0; }