Linguagem de Programação II Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação Classes Herança Herança de classes É um relacionamento existente entre classes que permite a criação de outras novas classes a partir das classes existentes Reutilização de código Poupa tempo de programação Classes criadas a partir de outras herdam algumas ou todas as caracteristicas (variaveis-membro e métodos) Herança de classes Classe-base: classe que dá origem a outras Classes derivadas: aquelas que nascem a partir de uma classe-base Classes derivadas podem criar métodos ou atributos para atender necessidades especificas Estrutura de uma classe e suas classes derivadas é chamada de hierarquia de classes Heranças simples Tipo mais simples de herança class classe-deriv : tipo classe-base declaração Onde: class: palavra reservada classe-deriv: nome da classe derivada tipo: tipo de herança ou derivação. Diz respeito aonde os membros da classe-base poderão ser utilizados. Pode ser public, protected ou private classe-base: nome da classe base declaração: declaração da classe derivada Heranças simples Classe base Classe derivada Representação grafica class carro { public: void exibe(); private: char marca[12]; char modelo[10]; }; class novo-carro :public carro { public: exibe_novo(); private: int anofab; } Tipos de herança Public Membros publicos da classe-base se tornam publicos na classe derivada Membros protegidos na classe-base se tornam protegidos na classe derivada Membros privados na classe-base se tornam privados na classe derivada, podendo ser acessados apenas pelos metodos publicos e protegidos (da seção protected) da classe-base Construtores da classe-base não são herdados na classe derivada. Se não chamar de forma explicita o construtor da classe-base este será chamado por default para construir parte do novo ojeto Destrutores não são herdados Quando objeto é destruido executa destrutor da classe derivada e depois destrutor da classe-base Tipos de herança Private Membros púlicos e protegidos da classe-base torna-se privados na classe derivada Quer dizer que os metodos da classe base não se tornam publicos no objeto derivado Esses metodos podem ser usados dentro dos metodos da classe derivada É o tipo de herança default Tipos de herança Protected Variação da herança privada Membros publicos e protegidos da classe-base torna-se membros protegidos da classe derivada, podendo ser acessados pela classe derivada como se fossem publicos Para o resto do programa os membros protegidos serão considerados como privados, precisando ser acessados pelos métodos da classebase class carro { public: carro(char *, char *); char marca[12]; char modelo[10]; int main (){ novo_carro n1(“Ford”, “Focus”, 2002); n1.exibe_tudo(); return 0; } }; class novo_carro :public carro { public: novo_carro( char*, char*, int); void exibe_tudo(); private: int anofab; } carro :: carro( char * m1, char *m2){ strcpy(marca, m1); strcpy(modelo, m2); } novo_carro :: novo_carro(char *m1, char * m2, int a) : carro(m1, m2){ anotab = a; } void novo_carro ::exibe_tudo(){ cout << “Marca” << marca << endl; cout << “Modelo” << modelo << endl; cout << “Ano: “ << anofab << endl; } Exemplo com variaveis-membro definidas como public Informações adicionais Membros públicos da classe-base tornam-se membros públicos na classe derivada. Por isso método exibe_tudo mostra variáveis-membro da classe-base Protótipo contém referencia as duas variaveis-membro da classe-base seguidas da referência criada na classe derivada Informações adicionais Na definição do construtor novo_carro :: novo_carro(char *m1, char * m2, int a) : carro(m1, m2) carro(m1, m2) é uma lista de inicialização de variáveismembro que chama o construtor da classe-base. Um construtor da classe derivada precisa chamar o construtor da classe-base. Construtor da classe carro cria objeto do tipo carro e então construtor da classe derivada completa criação dos objetos Quando criado objeto da classe derivada cria-se primeiro o objeto da classe-base class carro { public: carro(char *, char *); void exibe(); private: char marca[12]; char modelo[10]; }; class novo_carro :public carro { public: novo_carro( char*, char*, int); void exibe_novo(); private: int anofab; }; int main() { carro carro1(“GM”, “Corsa”); novo_carro n1(“Ford”, “Focus”, 2002); carro1.exibe(); n1.exibe_novo(); n1.exibe(); // derivada chama base return 0; } void carro ::exibe(){ cout << “Marca” << marca << endl; cout << “Modelo” << modelo << endl; } carro :: carro( char * m1, char *m2){ strcpy(marca, m1); strcpy(modelo, m2); } novo_carro :: novo_carro(char *m1, char * m2, int a) : carro(m1, m2){ anotab = a; } void novo_carro ::exibe_novo(){ exibe(); // classe-base cout << “Ano: “ << anofab << endl; } Exemplo com variaveis-membro definidas como private Informações adicionais Entre uma classe-base e sua classe derivada existe um relacionamento que permite a um objeto da classe derivada chamar um metodo da classe-base o que é mostrado na linha n1.exibe() class carro { public: carro(char *, char *); protected: char marca[12]; char modelo[10]; }; class novo_carro :public carro { public: novo_carro( char*, char*, int); void exibe_tudo(); private: int anofab; }; void novo_carro ::exibe()_tudo{ cout << “Marca” << marca << endl; cout << “Modelo” << modelo << endl; cout << “Ano” << anofab << endl; } carro :: carro( char * m1, char *m2){ strcpy(marca, m1); strcpy(modelo, m2); } novo_carro :: novo_carro(char *m1, char * m2, int a) : carro(m1, m2){ anotab = a; } int main() { novo_carro ncarro1(“Ford”, “Focus”, 2002); ncarro1.exibe_tudo(); return 0; } Exemplo com variaveis-membro definidas como protected Informações adicionais A classe-base declara membros que são acessados pela classe derivada Como os membros protegidos da classe-base se tornam privados na classe derivada o método exibe_tudo() exibe as variáveis-membro da classe-base também Com membros iguais nas classes base e derivada, utiliza-se o operador de escopo :: para particularizar o acesso, no formato classe-base::membro e classe-derivada::membro Tipos de herança Tipo de herança Membros da classe Public Private Protected Publicos São publicos da São privados classe derivada da classe derivada São protegidos da classe derivada Privados Acessiveis via metodos da classe base Acessiveis via metodos da classe base Acessiveis via metodos da classe base Protegidos São protegidos na classe derivada São privados da classe derivada São protegidos da classe derivada Permissões de acesso Tipo de herança Classe derivada Public Private Protected Método acessa variável-membro pública da classe-base ? Sim Sim Sim Método acessa variável-membro privada da classe-base ? Não Não Não Método acessa variável-membro protegida da classe-base ? Sim Sim Sim Método chama método público da classe-base ? Sim Sim Sim Método chama método privado da classe-base ? Não Não Não Método chama método protegido da classe-base ? Sim Sim Sim Objeto acessa variável-membro pública da classe-base? Sim Não Não Objeto acessa variável-membro privada da classe-base? Não Não Não Objeto acessa variável-membro protegida da classe-base? Não Não Não Objeto chama método público da classe-base? Sim Não Não Objeto chama método público da classe-base? Não Não Não Objeto chama método público da classe-base? Não Não Não Classes-base abstratas É o relacionamento onde uma classe-base serve somente de modelo para outras classes derivadas Pessoa Sobrenome CPF Homem Mulher Idade Peso Estado civil class pessoa { public: void le_dados(); void exibe(); private: char snome[10]; char cpf[10]; }; class homem :public pessoa { public: void le_dados(); void exibe(); private: int idade; int peso; }; class mulher :public pessoa { public: void le_dados(); void exibe(); private: char est_civil[11]; }; int main() { homem homem1; mulher mulher1; cout << “informe dados homem”; homem1.le_dados(); cout << “informe dados mulher”; mulher1.le_dados(); homem1.exibe(); mulher1.exibe(); } void pessoa :: le_dados(){ cin >> snome; cin >> cpf; } void homem :: le_dados(){ pessoa:: le_dados(); cin >> idade; cin >> peso; } Informações adicionais Não foram criados objetos da classe pessoa. Essa classe é utilizada como uma classe geral cujo objetivo único é de atuar como uma base a partir da qual outras classes são derivadas. Classes cujo intuito é apenas derivar outras classes e sem a criação de objetos são chamadas classes-base abstratas ou simplesmente classes abstratas Os membros privados da classe abstrata somente podem ser acessados por ela mesmo (snome não pode ser acessado pela classe homem por exemplo) Mas no exemplo anterior o que impede a instanciação de um objeto da classe pessoa ?? Métodos virtuais e classes abstratas Esses slides serão vistos novamente quando for falado sobre métodos virtuais... Para impedir a criação de um objeto de uma classe-base abstrata basta declarar um método como virtual puro na classe-base Para um método tornar-se virtual puro basta acrescer = 0 no seu protótipo Uma vez declarado um método virtual puro em uma classebase , este deverá ser redefinido nas classes derivadas em que se deseja criar um objeto. Se qualquer das classes derivadas não redefinir o método virtual puro da classe-base, a classe derivada tornar-se-a uma classe abstrata class FormasGeo { public: virtual void desenhar() = 0; }; Método virtual puro torna a classe abstrata class quadrado :public FormasGeo { public: void desenhar(); }; class retangulo :public FormasGeo { public: void desenhar_2(); }; Redefinição do método Não redefiniu o método desenhar int main ( ){ quadrado quadrado1; // retangulo retangulo1; } Gera um erro pois classe retangulo se tornou abstrata class pessoa { public: virtual void le_dados() = 0; virtual void exibe() = 0; private: char snome[10]; char cpf[10]; }; class homem :public pessoa { public: void le_dados(); void exibe(); private: int idade; int peso; }; …… implementacao dos metodos …. int main() { homem homem1; pessoa p ; cout << “informe dados homem”; homem1.le_dados(); homem1.exibe(); } ERRO: Cannot declare variable p to be type of pessoa because the following virtual functions are abstract Classe final Existe momentos que não desejamos que uma classe possa ser derivada Essa classe é chamada de final Em C++ para criar uma classe final declara-se o destrutor como privado e cria-se um método estático retornando o endereço da instância criada. Implica no uso de ponteiros C++ não é elegante como Java nesse ponto Java possui a palavra reservada final para isso class Pessoa { int main(){ public: static Pessoa * Criar(){ return (new Pessoa()); } Pessoa *p; p = Pessoa::Criar(); p->le_dados(); p->mostra_dados(); void le_dados(); void mostra_dados(); private: ~Pessoa(); // destrutor string nome; }; /* Se descomentado gera erro class Homem :public Pessoa{ public: Homem(); } */ .... Implementacao dos metodos ... getch(); return 0; } Herança múltipla É a herança na qual uma classe é derivada a partir de várias classes-base Classe-base 1 Classe-base 2 Classe derivada Herança múltipla Em termos de sintaxe class P { .... }; class Q { .... }; class R : public P, public Q { ... }; Ambigüidade em herança múltipla Supondo a seguinte situação: duas classes-base contendo o métodos com o mesmo nome e uma classe derivada de ambas contendo métodos com nomes diferentes dos métodos das classes-base. Assim surge a questão: Como um objeto da classe derivada irá o método correto da classe-base ? Resposta: basta utiliza o operador de resolução de escopo :: class base1 { ... public: void exibe(); }; class base2 { ... public: void exibe(); }; class derivada: public base1, public base2 { ... }; int main () { derivada obj; obj.base1 :: exibe(); obj.base2 :: exibe(); // obj.exibe(); erro de compilação. Usar qual exibe?? }