next up previous contents
Next: Controle de acesso Up: Herança Previous: Herança   Sumário

Funcionamento básico

Para ilustrar como o mecanismo de herança é implementado em C ++, considere o seguinte exemplo, onde uma classe para representar veículo é definida.

indentation

class vehicle {
protected:
int wheels;
float weight;
public:
void initialize(int in_wheels, float in_weight);
int get_wheels(void);
float get_weight(void);
float wheel_loading(void);
};
Esta classe consiste de quatro métodos que manipulam os dois atributos relacionados ao número de rodas e peso do veículo. (A função do rótulo protected será discutida em mais detalhes na próxima seção.) Observe que esta definição é genérica o suficiente para representar estes aspectos tanto para uma bicicleta quanto para um avião a jato. Esta é uma característica de classes base -- elas abstraem as propriedades de um grupo de classes.

A questão agora é: como representar (por exemplo) carros e caminhões? Eles são tipos de veículos, e uma declaração de classe que simplesmente repetisse as propriedades de veículos para carros ou caminhões iria simplesmente perder esta informação. Pior ainda: se a classe de veículos fosse atualizada para introduzir uma nova propriedade (atributo ou método), esta mudança não seria refletida nas classes de carros ou caminhões. Este tipo de mudança ocorre muitas vezes em projetos de grande porte, qunado há revisões de especificação para partes do projeto; em geral, é muito difícil controlar a propagação das modificações, o que geralmente envolve diversos grupos de trabalho.

Em C ++, como em outras linguagens de programação orientadas a objetos, há um mecanismo para conectar a definição da classe derivada com a classe base. Observe abaixo como a classe para carros é definida, assumindo-se que a classe vehicle foi definida como acima.

indentation


class car : public vehicle {
int passenger_load;
public:
void initialize(int in_wheels, float in_weight, int people = 4);
int passengers(void);
};

O mecanismo para indicar que a classe car é derivada da classe vehicle é dado pela sintaxe : public, como em

class Derived : public Base { ...};
que poderia ser lido como Derived é-um-tipo-de Base. Isto indica que a classe Derived é composta por toda a informação que está contida na classe Base, além de sua própria informação.

Na definição da classe car, indica-se que carro tem a mesma informação que um veículo, além de informação adicional sobre o número de passageiros que ele comporta. Note também que a classe car define um método de nome initialize, que era também um método da classe vehicle. Desta forma, quando initialize for ativado para um carro, a nova versão é que será ativada -- para outros veículos, a antiga versão continua valendo. Entretanto, esta forma de sobreposição de métodos não é aconselhada -- veja o Capítulo [*] para mais detalhes sobre este assunto.

Observe dos exemplos dados acima que não há nada de especial em relação a uma classe base: ela é simplesmente uma classe como qualquer outra, sem nenhuma indicação especial de que seus métodos e atributos serão herdados por outras classes. Da mesma forma, seria possível usar uma classe derivada como base para outras classes -- ou seja, toda uma hierarquia de classes pode ser implementada.

Similarmente, uma classe para representar caminhões poderia ser derivada de veículos como em

indentation

class truck : public vehicle {
int passenger_load;
float payload;
public:
void init_truck(int how_many = 2, float max_load = 24000.0);
float efficiency(void);
int passengers(void);
};
Observe que as características associadas a caminhões são diferentes daquelas de carros, e por este motivo é necessário definir uma nova classe derivada. É interessante ressaltar que não há nenhum relacionamento direto entre car e truck -- elas são apenas classes que foram derivadas de uma mesma classe base.

O exemplo abaixo ilustra a utilização destas classes em um programa C ++.

indentation

#include $<$iostream.h$>$
// ... definitions for classes vehicle, car, and truck here.

main()
{
vehicle unicycle;

unicycle.initialize(1, 12.5);
cout $\ll$ "The unicycle has " $\ll$
unicycle.get_wheels() $\ll$ " wheel.$\backslash$n";
cout $\ll$ "The unicycle's wheel loading is " $\ll$
unicycle.wheel_loading() $\ll$ " pounds on the single tire.$\backslash$n";
cout $\ll$ "The unicycle weighs " $\ll$
unicycle.get_weight() $\ll$ " pounds.$\backslash$n$\backslash$n";

car sedan;

sedan.initialize(4, 3500.0, 5);
cout $\ll$ "The sedan carries " $\ll$ sedan.passengers() $\ll$
" passengers.$\backslash$n";
cout $\ll$ "The sedan weighs " $\ll$ sedan.get_weight() $\ll$ " pounds.$\backslash$n";
cout $\ll$ "The sedan's wheel loading is " $\ll$
sedan.wheel_loading() $\ll$ " pounds per tire.$\backslash$n$\backslash$n";

truck semi;

semi.initialize(18, 12500.0);
semi.init_truck(1, 33675.0);
cout $\ll$ "The semi weighs " $\ll$ semi.get_weight() $\ll$ " pounds.$\backslash$n";
cout $\ll$ "The semi's efficiency is " $\ll$
100.0 $\ast$ semi.efficiency() $\ll$ " percent.$\backslash$n";
}
O resultado da execução deste programa é:
 The unicycle has 1 wheel.
 The unicycle's wheel loading is 12.5 pounds on the single tire
 The unicycle weighs 12.5 pounds.

 The sedan carries 5 passengers.
 The sedan weighs 3500 pounds.
 The sedan's wheel loading is 875 pounds per tire.

 The semi weighs 12500 pounds.
 The semi's efficiency is 72.929072 percent.

É interessante que se observe que um apontador declarado para a classe base (vehicle, neste exemplo) poderia ser usado para apontar para objetos tanto da classe base quanto para objetos das classes derivadas (car e truck, neste caso). Isto concorda com a intuição sobre hereditariedade -- afinal de contas, um carro continua sendo um veículo, e ao apontar para um carro está se apontando para um veículo.


next up previous contents
Next: Controle de acesso Up: Herança Previous: Herança   Sumário
Ivan Luiz Marques Ricarte 2001-06-01