Contents

Programação Orientada a Objetos - POO05


Programação Orientada a Objetos em C++ - POO05

Herança, Funções Virtuais e Polimorfismo


O polimorfismo é crucial para a programação orientada a objeto. Quando aplicado ao C++, o termo polimorfismo é usado para descrever o processo pelo qual diferentes implementações de uma função podem ser acessadas usando o mesmo nome.

Assim o polimorfismo também é caracterizado como "uma interface, múltiplos métodos". Em C++ o polimorfismo é suportado tanto em tempo de compilação com execução. Sobrecarga de operadores e de funções são exemplos de polimorfismo em tempo de compilação. O polimorfismo em tempo de execução no C++ é obtido com classes derivadas e funções virtuais.

Ponteiros Para Tipos Derivados.


Ponteiros para tipos bases e tipos derivados estão relacionados. Se você tem um tipo base chamado B_class e um tipo D_class derivado de B_class. Em C++ qualquer ponteiro declarado como ponteiro para B_class também pode ser ponteiro para D_class.

	B_class  *p;		// ponteiro para um objeto do tipo B_class
	B_class  B_obj;		//Objeto do tipo B_class
	D_class D_obj;		//Objeto do tipo D_class derivado de B_class
o seguinte é perfeitamente válido:
p= &B_obj; //p aponta para um objeto di tipo B_class p=&D_obj; //p aponta para um objeto do tipo D_class derivado de B_class
Usando p todos os elementos de D_obj herdados de B_obj podem ser acessados. Os elementos específicos de D_obj não podem ser acessados usando-se p. (a menos que se use um molde de tipo, a ser visto posteriormente). O exemplo que segue ilustra os conceitos:

clas29.cpp no FTP ou veja aqui...
clas29.cpp

No exemplo anterior, se você quer acessar os elementos definidos por um tipo derivado usando um ponteiro para o tipo base, deve moldá-lo em um ponteiro do tipo derivado. Assim para chamar a função mostra_tel() de D_obj, podemos usar:
	((D_class *)p) ->mostra_tel();

O conjunto externo de parênteses é necessário para associar o molde a p e não ao tipo de retorno de mostra_tel(). Esta forma é pouco usada.

Um ponteiro base pode ser usado para apontar para qualquer tipo de objeto derivado mas o inverso não é verdadeiro. Um ponteiro é incrementado e decrementado relativo ao seu tipo base. Assim quando um ponteiro para uma classe base está apontado para uma classe derivada, a incrementação ou decrementação não fará que ele aponte para o próximo objeto da classe derivada. Esta operação não funciona quando apontado para um objeto derivado.

Funções Virtuais


O polimorfismo em tempo de execução é obtido pelo uso de tipos derivados e funções virtuais. Função virtual é definida como virtual em uma class base e redefinida em uma ou mais classes derivadas. O que torna a função virtual especial é que quando uma é acessada usando-se um ponteiro da class base para um objeto da class derivada, o C++ determina qual a função a chamar no momento da execução. Uma função virtual é declarada como tal dentro da class base precedendo-se sua declaração com a palavra reservada virtual. Como primeiro exemplo de função virtual temos:

clas30.cpp no FTP ou veja aqui...
clas30.cpp



Por Que Usar Funções Virtuais?


A função virtual em combinação com os tipos derivados permite ao C++ suportar polimorfismo em tempo de execução. O polimorfismo deixa uma class generalizada especificar as funções que serão comuns a qualquer derivada daquela class enquanto permite a uma class derivada especificar a implementação de alguma ou todas funções. Assim temos o conceito de "uma interface, múltiplos métodos".
O exemplo que segue cria uma class base chamada figura, que é usada para armazenar as dimensões de vários objetos bidimensionais e para calcular as respectivas áreas. A função fixa_dim() é a função membro padrão, uma vez que sua operação será comum a todas as classes derivadas. Entretanto exibe_area() é declarada como virtual, já que varia a maneira como a área de cada objeto é calculada. O programa usa a classe figura para derivar outras classes específicas.

class31.cpp no FTP ou veja aqui....
clas31.cpp

Funções Virtuais Puras e Tipos Abstratos


Uma função virtual pura é aquela declarada em uma class base que não tenha definição relativa a base. Assim qualquer tipo derivado deve definir a sua própria versão. Para criar uma função virtual pura usa-se a forma geral,

  	virtual tipo nome-da-função (lista de parametros) = 0;
Assim no exemplo que segue, a função exibe_area() é uma função virtual pura.
class figura {
    double x, y;
public:
    void fixa_dim(double i, double j=0) {
           x=i;
           y=j;
     }
     virtual void exibe_area() = 0;  // virtual pura...
};

Quando se declara uma função virtual como pura, força-se qualquer class derivada a definir sua própria implementação, caso contrário da erro de compilação.

Se uma class tem no mínimo uma função virtual pura, ela é considerada abstrata. As classes abstratas tem uma característica importante. Não pode haver objeto daquela class. Assim uma class abstrata deve ser usada somente como uma base que outras classes herdarão. Entretanto mesmo a class base sendo abstrata, pode-se usa-la para declarar ponteiros necessários para suportar polimorfismo em tempo de execução.


Ligação Precoce Versus Ligação Tardia


Há dois termos que são normalmente usados quando se discute linguagens de programação orientada a objeto: ligação precoce e ligação tardia. Em C++ referem-se aos eventos que ocorrem no momento da compilação e no momento da execução respectivamente. Exemplos de ligação precoce incluem chamadas de funções padrões, chamadas de funções sobrecarregadas, chamadas de funções operadoras sobrecarregadas.

A ligação tardia é conseguida em C++ pelo uso da função virtual e tipos derivados. Pode ser usada para suportar uma interface comum enquanto permite a vários objetos que utilizam essa interface definir suas próprias implementações.

Construtores e Destrutores em Classes Derivadas


É possível para uma class base e para uma class derivada ter uma função construtora. Quando uma class derivada contém um construtor, o construtor base é executado antes da class derivada. Para função destrutora acontece o inverso, primeiro executa a função da classe derivada e depois da classe base. Também é possível uma class derivada ser ela própria usada como uma class base na criação de outra class derivada. Quando isso acontece, os construtores são executados na ordem de derivação e os destrutores na ordem inversa.
O exemplo que segue ilustra este conceito:

clas32.cpp no ftp ou veja aqui...
clas32.cpp


Classes de Múltiplas Bases


É possível especificar mais de uma class base quando se cria um tipo derivado. Para fazer isso, use uma lista de classes que serão herdadas separadas por vírgula. No exemplo que segue vemos que quando uma lista de classes bases é usada, os construtores são chamados da esquerda para a direita e os destrutores da direita para a esquerda.

clas33.cpp no ftp ou veja aqui...
clas33.cpp


Contents