H
ERANÇA O mecanismo de Herança da linguagem C++ permite que uma classe “herde” características (atributos e métodos) de outra classe. A classe da qual as características foram herdadas é chamada de classe base, enquanto a classe que herdou as características é usualmente chamada de classe derivada.Esse mecanismo é muito interessante, uma vez que permite que uma parte comum seja utilizada como base para várias classes, o que poupa um tempo precioso no desenvolvimento de aplicações.
Um exemplo bastante simples sobre o mecanismo de herança é apresentado no Programa 1. #include <iostream> #include <cmath> #include <string> using namespace std; class indutancia { public: float L; float RSE; float impedancia(float f) {
return sqrt(pow(2*M_PI*f*L,2) + pow(RSE,2)); }
};
class falante : public indutancia //falante é uma classe { //derivada de indutância public: string marca; string tipo; void imprime(void) {
cout << "Tipo: " << tipo << " Marca: " << marca << endl; cout << "L: " << L << " R: " << RSE;
cout << " R@20k: " << impedancia(20000) << endl; } }; int main(void) { falante spk1; spk1.marca = "SELENIUM"; spk1.tipo = "WOOFER"; spk1.L = 1e-7; spk1.RSE = 8; spk1.imprime(); system("PAUSE"); return 0;
Perceba como é a sintaxe para criar uma classe derivada a partir de uma classe base. Observe atentamente que os membros da classe base são utilizados como se pertencessem a classe derivada.
No exemplo do Programa 1, o falante é um tipo dedicado de indutância (indutor), portanto ele herda algumas características comuns a todos os indutores (o valor de indutância e a presença de uma resistência série equivalente). Porém, um alto-falante possui algumas características que o difere de um simples indutor. No caso, inseriram-se dois atributos – a marca e o tipo, além de um método específico para imprimir os dados do falante. Poder-se-ia, no exemplo acima, derivar mais uma classe da classe base indutância que serviria para representar um indutor de um filtro de linha. Esse indutor possui algumas peculiaridades que o diferencia de um alto-falante, embora ambos sejam indutores.
Exercício 1 Altere os atributos da classe base, tornando-os privados. O que ocorre?
Perceba que, quando os atributos da classe base são privados, a classe derivada não é capaz de acessá-los, mesmo sendo uma classe derivada da classe base. Isso pode parecer estranho, mas novamente, é uma maneira de assegurar que atributos importantes não sejam violados.
Por sorte, a maioria das classes que utilizam membros privados fornecem funções de acesso e/ou modificadoras. Uma solução para o “problema” do exercício 1 é apresentado no Programa 2 onde funções de acesso e modificadoras estão presentes na classe base.
#include <iostream> #include <cmath> #include <string> using namespace std; class indutancia { private: float L; float RSE; public:
float getL(void) { return L; } float getRSE(void) { return RSE; } void setL(float ind) { L = ind; } void setRSE(float r) { RSE = r; } float impedancia(float f)
{
return sqrt(pow(2*M_PI*f*L,2) + pow(RSE,2)); }
class falante : public indutancia { public: string marca; string tipo; void imprime(void) {
cout << "Tipo: " << tipo << " Marca: " << marca << endl; cout << "L: " << getL() << " R: " << getRSE();
cout << " R@20k: " << impedancia(20000) << endl; } }; int main(void) { falante spk1; spk1.marca = "SELENIUM"; spk1.tipo = "WOOFER";
spk1.setL(1e-7); spk1.setRSE(8); spk1.imprime();
system("PAUSE"); return 0;
}
Programa 2 Acessando membros privados da classe base.
Existe um modo mais fácil de permitir que classes derivadas acessem membros privados das classes bases.
A linguagem C++ disponibiliza um modificador de acesso chamado protected. Esse
modificador permite o livre acesso dos atributos por classes derivadas, porém, os atributos
protected são encarados como privados fora da classe. Compile o Programa 3.
#include <iostream> #include <cmath> #include <string> using namespace std; class A { private: int n1; protected: int n2; public: int n3; };
class B : public A //a classe B herda A { public:
void f(void) {
n1 = 10; //gera erro... n1 é privado na classe A n2 = 100; n3 = 1000; } }; int main(void) { B obj; obj.n3 = 100;
obj.n2 = 10; //gera erro... por ser membro protegido, n2 fora da classe é privado obj.n1 = 1; //gera erro... n1 é privado em A.
Perceba como o membro protegido n2 pode ser acessado pela classe derivada, porém,
diferentemente do membro público n3, não pode ser acessado diretamente fora da classe A ou da
classe B.
Note que, para classes básicas onde construtores padrão (criados pelo próprio compilador) são utilizados, nenhum cuidado extra é necessário. Isso é verdade também quando apenas o construtor da classe derivada é declarado. Analise o exemplo abaixo, onde um construtor é declarado e implementado apenas para uma classe derivada.
#include <iostream> #include <cmath> #include <string> using namespace std; class indutancia { public: float L; float RSE; float impedancia(float f) {
return sqrt(pow(2*M_PI*f*L,2) + pow(RSE,2)); }
};
class falante : public indutancia { public: string marca; string tipo; void imprime(void) {
cout << "Tipo: " << tipo << " Marca: " << marca << endl; cout << "L: " << L << " R: " << RSE;
cout << " R@20k: " << impedancia(20000) << endl; }
falante(string str1, string str2, float ind, float r) //construtor {
tipo = str1; marca = str2; L = ind; RSE = r; }
};
int main(void) {
falante spk1("WOOFER", "SELENIUM", 1e-7, 4); spk1.imprime();
system("PAUSE"); return 0;
}
Programa 4 Construtores e Herança.
Porém, quando um construtor da classe base é definido, é necessário utilizar uma sintaxe um pouco mais complexa e menos intuitiva para escrever o construtor da classe derivada. Observe o Programa 5, que funcionalmente é igual ao Programa 4.
#include <iostream> #include <cmath> #include <string> using namespace std; class indutancia { public: float L; float RSE; float impedancia(float f) {
return sqrt(pow(2*M_PI*f*L,2) + pow(RSE,2)); }
//construtor classe base
indutancia(float ind, float r) { L = ind; RSE = r; } };
class falante : public indutancia //falante é uma classe { //derivada de indutância public: string marca; string tipo; void imprime(void) {
cout << "Tipo: " << tipo << " Marca: " << marca << endl; cout << "L: " << L << " R: " << RSE;
cout << " R@20k: " << impedancia(20000) << endl; }
//construtor da classe derivada
falante(string str1, string str2, float ind, float r) : indutancia(ind, r) { tipo = str1; marca = str2; } }; int main(void) {
falante spk1("WOOFER", "SELENIUM", 1e-7, 4); spk1.imprime();
system("PAUSE"); return 0;
}
Programa 5 Construtores e Herança 2.
Mais sobre construtores e herança pode ser encontrado na bibliografia básica da disciplina. Exercício 2 Crie uma classe base para um capacitor, que contenha o valor da capacitância, da resistência série equivalente e da resistência de fuga do capacitor.
Exercício 3 Utilize o mecanismo de herança para definir duas classes derivadas:
Uma que represente um capacitor eletrolítico (que possui um valor de indutância que deve ser considerado, além de uma faixa estreita e importante de tensão máxima que pode ser aplicada).
A outra classe deve modelar um capacitor variável utilizado para sintonia de rádio. Crie um atributo que indique o valor (0 a 100%) da capacitância nominal utilizada, além de funções para obter o valor de capacitância momentânea desse capacitor.