Baixe o app para aproveitar ainda mais
Prévia do material em texto
Escola Politécnica da Universidade de São Paulo Escola Politécnica da Universidade de São Paulo Laboratório de Programação Orientada a Objetos para Engenharia Elétrica Aula 5: Construtores e Destrutores PCS3111 Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes 2 Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes 3 Construtores ! Em qualquer linguagem de programação, quando se deseja utilizar uma variável num programa deve- se realizar ao menos duas operações: • Criação da variável: alocação de espaço na memória e ligação deste espaço a um nome • Inicialização da variável: colocar os valores iniciais e assegurar as condições iniciais necessárias para sua correta utilização ! Em POO, estas operações às vezes são mais complexas, pois temos que criar e inicializar objetos! ! Encapsulamento permite “esconder” estas operações do usuário do objeto. 4 Construtores ! Usualmente, na maioria das linguagens de programação, a criação se dá através de um comando de declaração ! Já a inicialização se dá num ou mais comando(s) de atribuição ! Problemas ocorrem se o usuário esquece de inicializar uma variável (ou se o faz mais de uma vez) 5 maximo = 10; Inicialização int maximo; Criação while (i < maximo) {...} Construtores ! É um método chamado automaticamente quando o objeto é criado, e contém as instruções para a sua correta inicialização • Inicializar atributos com os valores adequados • Eventualmente, criar objetos internos ... ! Com isto, se garante que um objeto nunca será utilizado sem que esteja pronto para tal ! Do ponto de vista da linguagem, trata-se de um método como outro qualquer, com algumas singularidades 6 Construtores em C++ ! Declaração do construtor • Método tem o mesmo nome da classe • Método não tem retorno • Método pode ter parâmetros 7 1 class Sensor { 2 public: 3 int numero; 4 Residencia *residencia; 5 6 Sensor (int numero, Residencia *residencia); 7 void detectarAcao(); 8 }; Construtor Construtores em C++ ! Ocorre aqui uma situação interessante. Para ser mais legível, os parâmetros para inicialização têm os mesmos nomes dos atributos do objeto. Mas quando se deseja implementar o construtor, como se pode diferenciá-los? 8 1 class Sensor { 2 public: 3 int numero; 4 Residencia *residencia; 5 6 Sensor (int numero, Residencia *residencia); 7 void detectarAcao(); 8 }; Construtor Construtores em C++ ! Geralmente, na maioria das linguagens OO, o recipiente da mensagem não aparece explicitamente na chamada do método ! Quando se necessita acessar o recipiente de uma mensagem em um método, utiliza-se uma pseudo-variável • Trata-se de uma variável que não necessita ser declarada e cujo valor não pode ser alterado ! Em C++, esta pseudo-variável denomina-se this (conforme introduzido na Aula 2) 9 Construtores em C++ ! Implementação do construtor • Opção 1 ! Diferencia o atributo do parâmetro usando this • Permite nomes mais adequados 10 1 Sensor::Sensor(int numero, Residencia *residencia) { 2 this->numero = numero; 3 this->residencia = residencia; 4 } Construtores em C++ ! Implementação do construtor • Opção 2 (recomendada) ! Ainda usa os nomes dos atributos como parâmetros • Facilita a leitura para quem usa o construtor 11 Sensor::Sensor (int numero, Residencia *residencia) : numero (numero), residencia (residencia) { // ... } Atributo Parâmetro Atributo Parâmetro Construtores em C++ ! Chamada do construtor ! O que ocorreria neste caso? 12 Residencia *r = new Residencia (); // Construtor sem parâmetros Sensor *s1 = new Sensor(1, r); // Construtor com parâmetros Sensor *s2 = new Sensor(2, r); Residencia *r; Sensor *s1 = new Sensor(1, r); Sensor *s2 = new Sensor(2, r); NULL ! Representa um ponteiro que aponta para nenhum valor ! explicado na Aula 2 13 1 #include <iostream> 2 ... 3 4 int main (int argc, char** argv) { 5 int *p; // endereço indefinido 6 p = NULL; // nenhum valor 7 8 if (p == NULL) { // é possível testar 9 ... 10 } 11 } Necessário fazer um include para usar o NULL (Está definido em várias bibliotecas) Construtores em C++ ! Se quisermos criar um Sensor fora de uma Residência, podemos indicar um objeto vazio usando NULL: 14 Sensor *s1 = new Sensor(1, NULL); Sensor *s2 = new Sensor(2, NULL); Construtores em C++ ! Se um construtor não for especificado, o C++ cria um construtor padrão (sem parâmetros) • Usa-se um construtor padrão quando não houver nada a ser feito na criação 15 class Residencia { public: Residencia(); }; class Residencia { }; Equivalente a Observação: se for declarado um construtor sem parâmetros, ele precisará ser implementado! Construtores ! Quais parâmetros o construtor deve ter? • Depende do uso! ! Algumas perguntas • Que informações são necessárias para inicializar o objeto? • O valor do atributo depende do objeto ou pode ser padrão? • Exemplo ! classe Sensor • Atributos: numero (int) e residencia (Residencia*) ! classe Residência • Atributos: l (ListaLigadaSensores) e disparado (bool) 16 Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes 17 Destrutores ! Em certos casos, seria útil também realizar certas operações ao término do ciclo de vida de um objeto, quando este deve ser destruído ! Analogamente ao caso dos construtores, em POO existem métodos que são automaticamente executados nestes casos ! Tais métodos denominam-se destrutores 18 Destrutores ! Método chamado quando um objeto é destruído • Ele deve liberar os recursos usados ! Declaração de um destrutor em C++ • Não tem parâmetros e nem retorno • Nome da classe com ~ 19 1 class Sensor { 2 public: 3 ... 4 5 Sensor (int numero, Residencia *residencia); // Construtor 6 ~Sensor(); // Destrutor 7 ... 8 }; Destrutor Destrutores em C++ ! Implementação do destrutor ! Quando um objeto é destruído? ! Quando um destrutor é executado? 20 1 Sensor::~Sensor() { 2 cout << "Destruido" << endl; 3 } Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes 21 0x000000 ... 0x000080 0x000084 0x000088 0x00008C ... Ciclo de vida de um objeto ! Criação, uso e destruição 22 s: Sensor Criação numero = 3 residencia = r detectarAcao() Destruição 0x000000 ... ? 0x000080 ? 0x000084 0x000088 0x00008C ... detectarAcao() Memória Atribui valor Atribui valor Executa método Execu ta mét odo 0x000000 ... 3 0x000080 ? 0x000084 0x000088 0x00008C ... 0x000000 ... 3 0x000080 Posição de r 0x000084 0x000088 0x00008C ... Escopo ! Um bloco define o escopo de uma variável • Bloco: conjunto de comandos entre "{" e "}" • A variável e o objeto existem naquele bloco 23 1 if (i < maximo) 2 { 3 int j; 4 j = maximo; 5 } 6 7 if (j > 2) ...; Erro de compilação. A variável “j" não está declarada neste escopo! Aqui a variável j é desalocada da memória Alocação de memória ! Problema: alocação de memória • O C++ não sabequantos objetos serão criados antes da execução • Mesmo problema com vetores 24 1 int vetor1[50]; 2 3 int quantidade; 4 cin >> quantidade; 5 int vetor2[quantidade]; Válido Problema: qual o tamanho? Alocação de memória ! Alocação estática de vetores 25 int inteiros [5]; // Vetor para 5 inteiros Sensor *sensores [5]; // Vetor para 5 sensores sensores sensores[0] sensores[1] sensores[2] sensores[3] sensores[4] for (int i=0; i<5; i++) { inteiros[i] = i+1; sensores[i] = new Sensor(i, NULL); } Alocação de memória ! O C++ permite alocar memória dinamicamente • Usa uma área especial de memória ! Chamada heap / free store / memória dinâmica ! Programador deve gerenciar a memória • Alocar o elemento → new • Desalocar o elemento → delete 26 Alocação de memória ! New: alocação no heap • Retorna um identificador para o elemento criado • Chama o construtor ! Delete: desalocação do elemento no heap • Chama o destrutor 27 int *p = new int; Residencia *r = new Residencia (); Sensor *s1 = new Sensor; // Construtor sem parâmetros Sensor *s2 = new Sensor(5, r); // Construtor com parâmetros int *p = new int; ... delete p; Sensor *s1 = new Sensor; ... delete s1; Alocação de memória ! Alocação dinâmica de vetores 28 int maximo; cin << maximo; int *inteiros = new int[maximo]; // Vetor para max. inteiros Sensor **sensores = new Sensor* [maximo]; // Vetor para max. sensores sensores sensores[0] sensores[1] sensores[2] sensores[3] sensores[4] for (int i=0; i<maximo; i++) { inteiros[i] = i+1; sensores[i] = new Sensor(i, NULL); } Alocação de memória ! Desalocação de vetores 29 int *inteiros = new int[10]; ... delete[] inteiros; Sensor **sensores = new Sensor*[maximo]; ... delete[] sensores; Gerenciamento de memória ! Regra geral ! Problemas comuns • Objetos criados (new) mas não apagados (delete) ! Memory leak • Objeto apagado prematuramente ! A área de memória pode ter outro uso! • Objeto apagado mais de uma vez ! Não se sabe o que será apagado na segunda vez 30 Toda a vez que algo for alocado (new), ele deve ser em algum momento desalocado (delete)! Gerenciamento de memória ! Em algumas linguagens o ambiente gerencia a destruição dos objetos • Exemplo: Java, Perl, Python e C# • Vantagem: facilidade • Desvantagens: ! O ambiente precisa controlar os objetos: recursos ! A destruição é feita quando o ambiente quer ! Compromisso entre controle X facilidade 31 Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes 32 Constantes ! É possível definir constantes em C++ • Modificador const ! O valor da constante deve ser atribuído na declaração da variável 33 const int x = 0; // x não pode // ser alterado const Sensor *s = new Sensor(1, new Residencia); // s não pode // ser alterado x = 3; s->numero = 4; Erro de compilação. Inválido alterar uma constante. Constantes ! Um parâmetro pode ser uma constante • Não pode ser alterado pelo método • Verificação de erros em tempo de compilação • Exemplo 34 void processar(const Sensor *s) { ... s->numero = 4; } Erro de compilação. Objeto não pode ser alterado Constantes ! O retorno de uma função / método também pode ser uma constante 35 const int* criarVetor() { return new int[3]; } const int *vetor = criarVetor(); vetor[0] = 3; Erro de compilação. Não pode ser alterado Compilador obriga que a variável seja um const int * Constantes ! É possível definir que um método não pode alterar o objeto 36 class Sensor { public: int numero; Residencia *residencia; Sensor(int numero, Residencia *residencia); void detectarAcao() const; }; Não pode alterar os atributos void Sensor::detectarAcao() const { ... this->numero = 0; } Erro em tempo de compilação Agenda 1. Construtores 2. Destrutores 3. Escopo e gerenciamento de memória 4. Constantes ADENDO: Entrada de dados pelo teclado em C++ 37 Detalhes de C++ ! Obter uma string do teclado • Solução: função getline ! Uso: getline(cin, umaString) • Não captura o '\n' ! Necessário fazer #include <string> • ...o texto digitado anteriormente por um cin pode ser "capturado" pelo getline... ! Necessário ignorar os caracteres digitados anteriormente • Método ignore do cin 38 string texto1, texto2; cin >> texto1; cin >> texto2; Não considera texto com espaço... A próxima palavra digitada vai para texto2 cin.ignore(100, '\n') // ignora 100 caracteres ou até // encontrar um '\n' Detalhes de C++ ! Exemplo 39 1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main (int argc, char** argv) { 6 string texto1, texto2; 7 cin >> texto1; 8 9 cin.ignore (100, '\n'); 10 getline (cin, texto2); 11 12 cout << texto1 << endl; 13 cout << texto2 << endl; 14 return 0; 15 } Bibliografia ! Budd, T. An Introduction to Object-Oriented Programming. Addison-Wesley, 3rd ed. 2002. Capítulo 5. ! Lafore, R. Object-Oriented Programming in C++. Sams, 4th ed. 2002. Capítulo 6. ! Savitch, W. C++ Absoluto. Pearson, 1st ed. 2003. Seções 7.1 e 10.3. 40
Compartilhar