Programar em C++/Herança
De Wikibooks
Tabela de conteúdo |
[editar] Inherance (Herança)
Inherance é um dos pontos chave do OOP- Object Oriented Programming. a ideia da Inherance é facilitar a programação. Imaginemos que tínhamos definido já uma classe que definia o comportamento de um dado objecto da vida real, por exemplo, animais. se me ocorrer ter de fazer uma nova classe que tenta modelar o comportamento de um leão.
Uma vez que eu sei que o leão vai ter características da classe animais, o que eu poderia fazer era aproveitar a classe dos animais e fazer com que a classe leão derive da de animais.
ou seja no fim de contas fazer inherance é termos 2 classes que são próximas, têm características mutuas, mas não são iguais, existe uma especificação numa delas, portanto em vez de estar a escrever código (que nos programas reais isso leva muitas linhas e muitos dias de programação) posso poupar algum tempo e dizer que uma classe herda da outra classe e depois basta-me fazer o código para a espcificação.
[editar] sintax
class derived-class : access base-class {
body of new class
}
Repare que temos o operador : Repare que o Access é optional mas claro se presente tem de ser public, private ou protected.
fazer fazer o exemplo completo
// Demonstrate inheritance.
#include <iostream>
using namespace std;
class road_vehicle // Define a base class for vehicles.
{
int wheels;
int passengers;
public:
void set_wheels(int num) { wheels = num; }
int get_wheels() { return wheels; }
void set_pass(int num) { passengers = num; }
int get_pass() { return passengers; }
};
class truck : public road_vehicle // Define a truck.
{
int cargo;
public:
void set_cargo(int size) { cargo = size; }
int get_cargo() { return cargo; }
void show();
};
enum type {car, van, wagon};
class automobile : public road_vehicle // Define an automoble.
{
enum type car_type;
public:
void set_type(type t) { car_type = t; }
enum type get_type() { return car_type; }
void show();
};
void truck::show()
{
cout << "wheels: " << get_wheels() << "\n";
cout << "passengers: " << get_pass() << "\n";
cout << "cargo capacity in liters: " << cargo << "\n";
}
void automobile::show()
{
cout << "wheels: " << get_wheels() << "\n";
cout << "passengers: " << get_pass() << "\n";
cout << "type: ";
switch(get_type())
{
case van: cout << "van\n";
break;
case car: cout << "car\n";
break;
case wagon: cout << "wagon\n";
}
}
int main()
{
truck t1, t2;
automobile c;
t1.set_wheels(18);
t1.set_pass(2);
t1.set_cargo(3200);
t2.set_wheels(6);
t2.set_pass(3);
t2.set_cargo(1200);
t1.show();
cout << "\n";
t2.show();
cout << "\n";
c.set_wheels(4);
c.set_pass(6);
c.set_type(van);
c.show();
system ("pause");
return 0;
}
temos a classe base: road_vehicle temos 2 classes derivadas: a truck e a automobile.
repare ainda um pormenor: tanto a classe truck e a automobile. têm como função membro a show(). mas cada uma não interfere com a outra. isto ilustra um outro aspecto do polimorfismo.
[editar] base class Access Control.
Quando uma classe herda outra, os membros da classe base ficam membros da classe derivada. o acesso dos membros da classe base à classe derivada é determinado pelo especificador de acesso: public, private e protected. Por defaut temos o private, ou seja como temos a opção de não explicitar o especificador de acesso, sabes que eles são private por defaut.
Assim ficamos com as possíveis combinações
- base class inheret as Public:
- Public membrer da base classe:
- É como tivéssemos a fazer copy dos public members da classe base e os colocássemos como public na classe derivada
- Private membrer da base classe:
- não são passados
- Protected membrer da base classe:
- se tivermos protected members na classe eles são como copiados para a classe derivada como protected.
- Public membrer da base classe:
- base class inheret as Private:
- Public membrer da base classe:
É como tivéssemos a fazer copy dos public members da classe base e os colocássemos como **private na classe derivada
-
- Private membrer da base classe:
- não são passados
- Protected membrer da base classe:
- è como estivéssemos a copiar os protected members da classe base e os colocássemos como private na classe derivada.
- Private membrer da base classe:
- base class inheret as Protected:
- Public membrer da base classe:
- É como tivéssemos a fazer copy dos public members da classe base e os colocássemos como protected na classe derivada
- Private membrer da base classe:
- não são passados
- Protected membrer da base classe:
- Assim é como estivéssemos a copiar os protected members da classe base e os colocássemos como protected na classe derivada.
- Public membrer da base classe:
aqui está um exemplo muito simples
#include <iostream>
using namespace std;
class base
{
int i, j;
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << "\n"; }
};
class derived : public base
{
int k;
public:
derived(int x) { k = x; }
void showk() { cout << k << "\n"; }
};
int main()
{
derived ob(3);
ob.set(1, 2); // access member of base
ob.show(); // access member of base
ob.showk(); // uses member of derived class
system ("pause");
return 0;
}
#include <iostream>
using namespace std;
class base
{
int i, j;
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << "\n"; }
};
class derived : private base
{
int k;
public:
derived(int x) { k = x; }
void showk() { cout << k << "\n"; }
};
int main()
{
derived ob(3);
ob.set(1, 2); // Error, can't access set()
ob.show(); // Error, can't access show()
ob.showk(); // uses member of derived class
system ("pause");
return 0;
}
conseguimos aceder á função set() e show() porque é heradada como public Agora já não porque está como private
[editar] Herdar múltiplas classes base
Podemos ter a situação em que uma classe possa herdar de várias classes base.
// An example of multiple base classes.
#include <iostream>
using namespace std;
class base1
{
protected:
int x;
public:
void showx() { cout << x << "\n"; }
};
class base2
{
protected:
int y;
public:
void showy() { cout << y << "\n"; }
};
class derived: public base1, public base2 // Inherit multiple base classes.
{
public:
void set(int i, int j) { x = i; y = j; }
};
int main()
{
derived ob;
ob.set(10, 20); // provided by derived
ob.showx(); // from base1
ob.showy(); // from base2
system ("pause");
return 0;
}
repare que utilizamos o operador comma (virgula) para dizer que herdamos várias classes.
Pergunta: e quando queremos herdar uma classe como public e outra como private ou protected. Basta preceder a classe com o seu especificador de acesso
[editar] Constructors e destructors
Agora temos a questão quando é que os constructors são chamados quando eles são herdados?
- quando um objecto da classe derivada é chamado, o constructor da base class é chamado primeiro seguido do constructor da classe derivada.
- quando o objecto da classe derivada é destruído, o seu destructor é chamado primeiro seguido do destructor da base class
vamos ver isto. caso em que termos herança sequencial A-B-C
#include <iostream>
using namespace std;
class base
{
public:
base() { cout << "Constructing base\n"; }
~base() { cout << "Destructing base\n"; }
};
class derived1 : public base
{
public:
derived1() { cout << "Constructing derived1\n"; }
~derived1() { cout << "Destructing derived1\n"; }
};
class derived2: public derived1
{
public:
derived2() { cout << "Constructing derived2\n"; }
~derived2() { cout << "Destructing derived2\n"; }
};
int main()
{
derived2 ob; // construct and destruct ob
system ("pause");
return 0;
}
este exemplo está muito giro!!
caso de múltipla herança A- B e C
#include <iostream>
using namespace std;
class base1
{
public:
base1() { cout << "Constructing base1\n"; }
~base1() { cout << "Destructing base1\n"; }
};
class base2
{
public:
base2() { cout << "Constructing base2\n"; }
~base2() { cout << "Destructing base2\n"; }
};
class derived: public base2,public base1
{
public:
derived() { cout << "Constructing derived\n"; }
~derived() { cout << "Destructing derived\n"; }
};
int main()
{
derived ob;// construct and destruct ob
system ("pause");
return 0;
}
repare que aqui é a ordem da esquerda para a direita que os constructors são executados na
[editar] Passando parâmetros para a base class constructors
a sintax é:
derived-constructor(arg-list) : base1(arg-list), base2(arg-list), ...baseN(arg-list);
{
body of derived constructor
}
este exemplo está complexo, atenção!
#include <iostream>
using namespace std;
class base
{
protected:
int i;
public:
base(int x) { i = x; cout << "Constructing base\n"; }
~base() { cout << "Destructing base\n"; }
};
class derived: public base
{
int j;
public:
derived(int x, int y): base(y) { j = x; cout << "Constructing derived\n"; }// derived uses x; y is passed along to base.
~derived() { cout << "Destructing derived\n"; }
void show() { cout << i << " " << j << "\n"; }
};
int main()
{
derived ob(3, 4);
ob.show(); // displays 4 3
system ("pause");
return 0;
}
aqui o derived constructor é declarado com 2 argumentos (x e y). no entanto a função derived() usa apenas um.
aqui vai mais um exemplo.
#include <iostream>
using namespace std;
class base1
{
protected:
int i;
public:
base1(int x) { i = x; cout << "Constructing base1\n"; }
~base1() { cout << "Destructing base1\n"; }
};
class base2
{
protected:
int k;
public:
base2(int x) { k = x; cout << "Constructing base2\n"; }
~base2() { cout << "Destructing base2\n"; }
};
class derived: public base1, public base2
{
int j;
public:
derived(int x, int y, int z): base1(y), base2(z)
{ j = x; cout << "Constructing derived\n"; }
~derived() { cout << "Destructing derived\n"; }
void show() { cout << i << " " << j << " " << k << "\n"; }
};
int main()
{
derived ob(3, 4, 5);
ob.show(); // displays 4 3 5
system ("pause");
return 0;
}
[editar] Granting Access
recordam-se que os private members da classe base nunca são acedidos quer fora do programa quer mesmo sendo herdados. são apenas pelos restantes members da classe!
podemos no entanto conceder o mesmo nível de acesso que tinham na base classe aos membros herdados.
- podemos conseguir isto através da palavra “using” e esta é a maneira recomendada, mas vamos deixar isto para o capitulo dos namespace
- ou então usar um método que já está em desuso, que eu nem vou abordar.
[editar] Virtual base class
consideremos o seguinte programa:
// This program contains an error and will not compile.
#include <iostream>
using namespace std;
class base
{
public:
int i;
};
class derived1 : public base // derived1 inherits base.
{
public:
int j;
};
class derived2 : public base // derived2 inherits base.
{
public:
int k;
};
class derived3 : public derived1, public derived2 /* derived3 inherits both derived1 and derived2. This means that there are two copies of base in derived3! */
{
public:
int sum;
};
int main()
{
derived3 ob;
ob.i = 10; // this is ambiguous; which i???
ob.j = 20
ob.k = 30;
ob.sum = ob.i + ob.j + ob.k;// i ambiguous here, too
cout << ob.i << " ";// also ambiguous, which i?
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
system ("pause");
return 0;
}
as classes derived1 e derived 2 herdam a classe base a classe derived3 herda quer derived 1 e derived2. como resultado temos 2 cópias da classe base presentes no objecto da derived 3. por exemplo presente na linha ob.i=20; isto resulta numa ambiguidade e o programa não vai compilar
há duas maneiras para remediar a situação 1. aplicar o operador scope resolution manualmente
// This program uses explicit scope resolution to select i.
#include <iostream>
using namespace std;
class base
{
public:
int i;
};
class derived1 : public base // derived1 inherits base.
{
public:
int j;
};
class derived2 : public base // derived2 inherits base.
{
public:
int k;
};
class derived3 : public derived1, public derived2 /* derived3 inherits both derived1 and derived2. This means that there are two copies of base in derived3! */
{
public:
int sum;
};
int main()
{
derived3 ob;
ob.derived1::i = 10; // scope resolved, use derived1's i
ob.j = 20;
ob.k = 30;
ob.sum = ob.derived1::i + ob.j + ob.k; // scope resolved
cout << ob.derived1::i << " "; // also resolved here
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
system ("pause");
return 0;
}
2. a segunda maneira é através do virtual base classes. quando temos 2 ou mais objectos que são derivados da mesma base class, podemos prevenir múltiplas cópias da base class declarando a base class como virtual quando ela é herdada exemplificando
// This program uses virtual base classes.
#include <iostream>
using namespace std;
class base
{
public:
int i;
};
class derived1 : virtual public base // derived1 inherits base as virtual.
{
public:
int j;
};
class derived2 : virtual public base // derived2 inherits base as virtual.
{
public:
int k;
};
class derived3 : public derived1, public derived2 /* derived3 inherits both derived1 and derived2. This time, there is only one copy of base class. */
{
public:
int sum;
};
int main()
{
derived3 ob;
ob.i = 10; // now unambiguous
ob.j = 20;
ob.k = 30;
ob.sum = ob.i + ob.j + ob.k;// unambiguous
cout << ob.i << " ";// unambiguous
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
system ("pause");
return 0;
}
repare que agora temos a palavra virtual antes da classe

