Classes bases e derivadas

51
Classes bases e derivadas considerar um programa que mostra as relações entr as que trabalham numa companhia/empresa. class CEmpregado { public: char* m_sNome; short m_nIdade; short m_nDep; double m_dSal; CEmpregado* m_pNext; // ... }; O campo m_pNext é um ponteiro para outro CEmpregad

description

Classes bases e derivadas. Vamos considerar um programa que mostra as relações entre as pessoas que trabalham numa companhia/empresa. class CEmpregado { public: char* m_sNome; short m_nIdade; short m_nDep; double m_dSal; CEmpregado* m_pNext; // ... };. - PowerPoint PPT Presentation

Transcript of Classes bases e derivadas

Page 1: Classes bases e derivadas

Classes bases e derivadasVamos considerar um programa que mostra as relações entre aspessoas que trabalham numa companhia/empresa.

class CEmpregado{public:

char* m_sNome;short m_nIdade;short m_nDep;double m_dSal;CEmpregado* m_pNext;// ...

};

O campo m_pNext é um ponteiro para outro CEmpregado.

Page 2: Classes bases e derivadas

Vamos agora definir um gestor.

class CGestor{ public:

CEmpregado m_Proprio;CEmpregado* m_lGrupo;short m_nNivel;// ... };

Um gestor é também um trabalhador. A informação acerca dotrabalhador é guardada no campo m_Proprio da classe CGestor.

O objectivo é definir um gestor como um trabalhador com algumainformação suplementar:

class CGestor : public CEmpregado{ public:

CEmpregado* m_lGrupo;short m_nNivel;// ... };

Page 3: Classes bases e derivadas

A classe CGestor é a classe derivada e a classe CEmpregado é a classebase. A classe CGestor tem todos os dados da classe CEmpregado e

outros dados como o m_lGrupo e o m_nNivel.

A derivação é normalmente representada de forma gráfica por umaseta da classe derivada para a classe base.

Diz-se que a classe derivada herda da classe base. A classe derivadaé maior do que a classe base no sentido em que armazena mais dados

e fornece mais funções.

Podemos agora criar uma lista de empregados que pode conterempregados ou gestores. Por exemplo:

Page 4: Classes bases e derivadas

CGestor g1, g2; CEmpregado e1, e2; CEmpregado* lista;

lista = &g1; // pôr g1 na listag1.m_pNext = &e1; // pôr e1 na listae1.m_pNext = &g2; // pôr g2 na listag2.m_pNext = &e2; // pôr e2 na listae2.m_pNext = 0; // a lista está terminada

Como um gestor é um empregado, o gestor pode ser usado comoempregado. Contudo, um empregado não é necessariamente um

gestor e por isso empregado não pode ser usado como gestor.

Page 5: Classes bases e derivadas

Geralmente se uma classe derivada possuir uma classe base públicaentão um ponteiro para a classe base pode conter o valor

do endereço de um objecto da classe derivada sem ser necessária umaconversão explícita. A conversão oposta, de um ponteiro para aclasse base para um ponteiro para a classe derivada, tem de ser

explícita. Por exemplo:

CGestor g3;CEmpregado* pe = &g3; // OkCEmpregado e4;CGestor* pg = &e4; // ERRO: um empregado não é um gestorpg->m_nLevel = 2; // aqui existe um problema porque e4 não

// tem o campo m_nNivel pg = (CGestor*)pe; // Ok porque pe é um ponteiro para o gestor g3pg->m_nNivel = 2; // Ok: pg é um ponteiro para um gestor que

//tem o campo m_nNivel

Page 6: Classes bases e derivadas

Se a classe base possuir um construtor, ele deve ser invocado; no caso deste possuir argumentos, então estes devem ser fornecidos.

Os objectos de uma classe são construídos de forma ascendente:primeiro os membros (subobjectos) da classe base, depois a classe

base, e finalmente, a classe derivada.

Os membros e as classes base são construídos na ordem pela qualsão declarados na classe e destruídos pela ordem inversa.

Page 7: Classes bases e derivadas

class CEmpregado {// ...

public: CEmpregado (char* n, int d);// ...

};class CGestor : public CEmpregado {

// ...public:

CGestor (char* n, int l, int d);// ...

};

CGestor :: CGestor (char* n, int l, int d): CEmpregado (n, d), m_nLevel (l), m_lGrupo(0) { ... }

CEmpregado :: CEmpregado(char* n, int d) : m_nDep (d){ ... }

12

3

4

Page 8: Classes bases e derivadas

Uma classe derivada pode também ser base de outras classes. Porexemplo:

class CEmpregado{ ... };class CGestor : public CEmpregado{ ... };class CDirector : public CGestor { ... };

A esta relação entre classes chama-se herança. A herança pode serrepresentada como uma árvore que pode ser mostrada graficamente.

Temporario CEmpregado

Consultante

temp_secCSecretario

CGestor

CDirector

Page 9: Classes bases e derivadas

Controlo de acesso

Uma classe base pode ser declarada com atributos private, protectede public, por exemplo:

class DERIVED_PUBLIC : public BASE {};class DERIVED_PROTECTED : protected BASE {};class DERIVED_PRIVATE : private BASE {};

Por defeito (se omitir o especificador de acesso) a herança em classes é privada.

O especificador de acesso controla- acesso aos membros da classe base;- conversão de ponteiros e referências do tipo derivado para o tipo base (upcasting).

Page 10: Classes bases e derivadas

Na herança pública todos os membros públicos da classe base permanecem membros públicos na classe derivada; os membros protegidos da classe base permanecem membros protegidos na

classe derivada e finalmente, os membros privados da classe base não são acessíveis na classe derivada.

Se a classe B é a base pública da classe D, os membros públicos da B podem ser utilizados por qualquer função, e os membros protegidos da B podem ser usados por membros e amigos da D e por membros e amigos das classes derivadas da D.

Qualquer função pode efectuar o upcasting da D* para B*.

Herança pública

Page 11: Classes bases e derivadas

class c1{ public:

int pub_1;protected:

int prot_1;private:

int priv_1;};

class c2 : public c1{ public:

int pub_2;c2() { pub_1; prot_1; priv_1; }

protected:int prot_2;

private:int priv_2;

};

class c3 : public c2{ public:

int pub_3;c3() { pub_1; prot_1; priv_1; pub_2; prot_2; priv_2; }

protected:int prot_3;

private:int priv_3;

};

c1 a; a.pub_1; a.prot_1; a.priv_1;c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2;c3 c; c.pub_1; c.pub_2; c.pub_3; c.priv_2; c.prot_2; c_priv_3;c1* p = new c2;

Page 12: Classes bases e derivadas

Na herança protegida todos os membros públicos da classe base transformam-se nos membros protegidos na classe derivada; os

membros protegidos da classe base permanecem membros protegidos na classe derivada e finalmente, os membros privados da

classe base não são acessíveis na classe derivada.

Se a classe B é a base protegida da classe D, os membros públicos e protegidos da B só podem ser utilizados por membros e amigos da D e por membros e amigos das classes derivadas da D.

Apenas os membros e amigos da D e os membros e amigos das classes derivadas da D podem efectuar o upcasting da D* para B*.

Herança protegida

Page 13: Classes bases e derivadas

class c1{ public:

int pub_1;protected:

int prot_1;private:

int priv_1;};

class c2 : protected c1{ public:

int pub_2;c2() { pub_1; prot_1; priv_1; c1* p = new c2; }

protected:int prot_2;

private:int priv_2;

};

class c3 : protected c2{ public:

int pub_3;c3() { pub_1; prot_1; priv_1; pub_2; prot_2; priv_2; }

protected:int prot_3;

private:int priv_3;

};

c1 a; a.pub_1; a.prot_1; a.priv_1;c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2;c3 c; c.pub_1; c.pub_2; c.pub_3; c.priv_2; c.prot_2; c_priv_3;c1* p = new c2;

Page 14: Classes bases e derivadas

Na herança privada todos os membros públicos e protegidos da classe base transformam-se nos membros privados na classe

derivada; os membros privados da classe base não são acessíveis na classe derivada.

Se a classe B é a base privada da classe D, os membros públicos e protegidos da B só podem ser utilizados por membros e amigos da D.

Apenas os membros e amigos da D podem efectuar o upcasting da D* para B*.

Herança privada

Page 15: Classes bases e derivadas

class c1{ public:

int pub_1;protected:

int prot_1;private:

int priv_1;};

class c2 : private c1{ public:

int pub_2;c2() { pub_1; prot_1; priv_1; c1* p = new c2; }

protected:int prot_2;

private:int priv_2;

};

class c3 : private c2{ public:

int pub_3;c3() { pub_1; prot_1; priv_1; pub_2; prot_2; priv_2; }

protected:int prot_3;

private:int priv_3;

};

c1 a; a.pub_1; a.prot_1; a.priv_1;c2 b; b.pub_1; b.pub_2; b.prot_2; b.priv_2;c3 c; c.pub_1; c.pub_2; c.pub_3; c.priv_2; c.prot_2; c_priv_3;c1* p = new c2;

Page 16: Classes bases e derivadas

A classe BASE

public: o_membro_públicoprotected: o_membro_protegidoprivate: o_membro_privado

A classeDERIVADA

O atributo daclasse BASE

public

protected

privateO nível superior épúblico

A classe DERIVADApublic: o_membro_públicoprotected: o_membro_protegido.......................................

A classe DERIVADAprotected: o_membro_público o_membro_protegido.......................................

A classe DERIVADAprivate: o_membro_público o_membro_protegido.......................................

O a

lto

níve

l épr

oteg

ido

O a

lto

níve

l épr

ivad

o

Page 17: Classes bases e derivadas

Selecção do especificador de acesso às classes bases

O acesso público é o mais comum e significa que a classe derivada é um subtipo da classe base. Neste caso a classe derivada herda toda a interface pública da classe base (lista lista sorteada).

O acesso privado significa que a classe derivada está implementada em termos da classe base. Neste caso a classe derivada possui todos os dados e funcionalidade da classe base mas esta funcionalidade está escondida e só faz parte da implementação respectiva. O utilizador da classe derivada não tem acesso a esta funcionalidade e um objecto da classe derivada não pode ser processado como uma instância da classe base (lista pilha).

O acesso protegido significa “é um subtipo da classe base” para a classe derivada e os seus amigos e “está implementada em termos da classe base” para as outras classes. Neste caso a classe derivada também representa uma parte da implementação em vez de uma parte da interface da classe base. O acesso protegido utiliza-se quando se pretende derivar mais classes da classe derivada a fazer com que estas classes possam aceder à implementação da classe base.

Page 18: Classes bases e derivadas

Acesso público aos membros privados de uma classe

class c1{ public:

int pub_1;protected:

int prot_1;private:

int priv_1;};

class c2 : private c1{public:

int pub_2;c2() { pub_1; prot_1; priv_1; c1* p = new c2; }

using c1::priv_1; // errousing c1::prot_1;using c1::pub_1;

protected:int prot_2;

private:int priv_2;

};

c1 a; a.pub_1; a.prot_1; a.priv_1;c2 b; b.pub_1; b.pub_2; b.prot_1; b.prot_2; b.priv_2;

declaraçãousing

Page 19: Classes bases e derivadas

Classe abstractasClasse abstractas

Frequentemente precisamos de construir uma classe base só para fazer com que todas as classes derivadas desta possuam uma interface comum. Mas não queremos que alguém crie objectos desta classe base. A única coisa que permitimos ao utilizador é fazer upcast para a classe base a fim de aproveitar a sua interface. classe abstracta classe abstracta

Uma classe é abstracta se esta contém pelo menos uma função função virtual puravirtual pura.

Uma função virtual é pura se a sua declaração acaba com “= 0= 0”

virtual double Area () = 0;

Quando todas as funções de uma classe são virtuais puras, esta chama-se classe abstracta puraclasse abstracta pura.

Page 20: Classes bases e derivadas

Herança com as classe abstractasHerança com as classe abstractas

Quando derivamos uma classe da classe abstracta, a classe derivada deve implementar todas as funções virtuais puras.

Caso contrário, a classe derivada torna-se também abstracta. Consequentemente, é também impossível criar objectos da classe derivada.

Ao ver a declaração de uma função virtual pura, o compilador vai reservar uma célula na VTABLE da classe respectiva mas não vai por o endereço da função nesta célula. Neste caso a VTABLE será incompleta.

Se a VTABLE de uma classe está incompleta, torna-se impossível criar instâncias (objectos) desta classe.

Page 21: Classes bases e derivadas

Funções virtuais purasFunções virtuais puras

Normalmente, as funções virtuais puras não têm implementação na classe base.

Contudo, é possível criar implementações das funções virtuais puras.

De qualquer modo as classes derivadas devem implementar todas as funções virtuais puras. Contudo, o código comum pode ser posto na função respectiva da classe base e as funções das classes derivadas podem tirar proveito dele.

Page 22: Classes bases e derivadas

Destrutores virtuais purosDestrutores virtuais puros

Um destrutor pode ser virtual puro como qualquer outra função. Contudo há duas diferenças principais:

1) É necessário criar implementação do destrutor virtual puro.

2) Na classe derivada não é necessário criar a implementação do destrutor virtual puro.

Page 23: Classes bases e derivadas

class shape {//.................public:

virtual void draw() = 0;virtual void move(int,int) = 0;virtual void copy(int,int) = 0;// .................

};

class line : public shape {int x_begin,y_begin,x_end,y_end;

public:void draw();void move(int,int);void copy(int,int);// .................

};

Page 24: Classes bases e derivadas

Herança múltiplaA classe derivada pode ter duas (ou mais) classes bases. Neste casopodemos usar a seguinte notação:

class DERIVED :public BASE1,public BASE2,........................

{ };

BASE1 BASE2

DERIVED

Page 25: Classes bases e derivadas

class window_w_caption_and_scroll :public window_w_caption,public window_w_scroll

{ };

Neste caso temos a herança múltipla e a classe derivada tem:os membros desta classe;os membros públicos e protegidos de todas as classes bases.

Se podermos declarar várias classes bases, podem existir múltiplas instâncias da mesma classe base numa classe derivada. Por exemplo a classe window pode ser a classe base paraas classes window_w_caption e window_w_scroll:

class window_w_caption : public window { ... };class window_w_scroll : public window { ... };class window_w_caption_and_scroll :

public window_w_caption,public window_w_scroll { ... };

Page 26: Classes bases e derivadas

Neste caso a classe window_w_caption_and_scroll tem duas instâncias da classe base (window).

Em caso de ambiguidade devemos declarar a classe base como virtual, por exemplo:

class window_w_caption : virtual public window { ... };class window_w_scroll : virtual public window { ... };

window window window

window_w_caption

window_w_scroll

window_w_caption_and_scroll window_w_caption_and_scroll

window_w_caption

window_w_scroll

Page 27: Classes bases e derivadas

class window{ public:

std::string m_Caption;virtual ~window() {}

};class window_w_caption : public window { };

class window_w_scroll : public window { };

class window_w_caption_and_scroll : public window_w_caption, public window_w_scroll

{ };

int main (){

window_w_caption_and_scroll w;w.m_Caption;

return 0;}

virtual

Page 28: Classes bases e derivadas

pessoa

aluno

pessoa

trabalhador

aluno_trab

Page 29: Classes bases e derivadas

class pessoa { unsigned idade;

char* nome;public:

virtual void imprimir();pessoa(char*, unsigned);virtual ~pessoa();

};

class pessoa { unsigned idade;

string nome;public:

virtual void imprimir();pessoa(string&, unsigned);virtual ~pessoa();

};

class aluno : public pessoa { public:

aluno(string&, unsigned, unsigned);

virtual ~aluno();protected:

unsigned turma;};

class trabalhador : public pessoa { unsigned long Salario;public:

trabalhador(string&, unsigned,unsigned long);

virtual ~trabalhador();};

class aluno_trab : public aluno, public trabalhador {public:

aluno_trab(string&, unsigned,unsigned, unsigned long);

virtual ~aluno_trab();};

Page 30: Classes bases e derivadas

int main(){

aluno_trab a_t("Pedro", 23, 5135, 180000);a_t.imprimir();return 0;

}

pessoa

aluno

pessoa

trabalhador

aluno_trab

void pessoa::imprimir(){

cout << "Nome - " << nome << "; Idade - " << idade << endl;

}

Page 31: Classes bases e derivadas

class pessoa { unsigned idade;

char* nome;public:

virtual void imprimir();pessoa(char*, unsigned);virtual ~pessoa();

};

class pessoa { unsigned idade;

string nome;public:

virtual void imprimir();pessoa(string&, unsigned);virtual ~pessoa();

};

class aluno : virtual public pessoa { public:

aluno(string&, unsigned, unsigned);

virtual ~aluno();protected:

unsigned turma;};

class trabalhador : virtual public pessoa { unsigned long Salario;public:

trabalhador(string&, unsigned,unsigned long);

virtual ~trabalhador();};

class aluno_trab : public aluno, public trabalhador {public:

aluno_trab(string&, unsigned,unsigned, unsigned long);

virtual ~aluno_trab();};

Page 32: Classes bases e derivadas

alunotrabalhador

aluno_trab

pessoa

Page 33: Classes bases e derivadas

int main(int argc, char* argv[]){

aluno_trab a_t("Pedro", 23, 5135, 180000);a_t.imprimir();return 0;

} void pessoa::imprimir(){

cout << "Nome - " << nome << "; Idade - " << idade << endl;

}

Nome - Pedro; Idade - 23

alunotrabalhador

aluno_trab

pessoa

Page 34: Classes bases e derivadas

stringstring

stringstring é uma classe definida na biblioteca Standard C++. Esta classe serve para manipular arrays de caracteres.

Para criar objectos desta classe deve incluir o ficheiro de cabeçalho <string>.

#include <string> #include <iostream>

int main() {

using namespace std;string s1, s2; // strings vaziasstring s3 = "Olá"; // string inicializadastring s4("Bom dia"); // string inicializadas2 = "abc"; // Atribuição de um valor à strings1 = s3 + " " + s4; // Combinação de strings cout << s1 << endl;

return 0; }

Page 35: Classes bases e derivadas

Conversão explícita entre tipos (casting)Em C, quando se pretende converter uma expressão e num tipo T, utiliza-se a notação (T)e ou T(e).

C++ herdou esta possibilidade do C, contudo sem saber os tipos exactos do e e T, é impossível determinar qual foi a intenção do programador.

Em C++ existem 4 operadores de conversão que especificam claramente o tipo de conversão pretendido.

Page 36: Classes bases e derivadas

static_cast

O operador static_cast realiza conversões entre tipos relacionados tais como: - conversão entre ponteiros dos tipos pertencentes a mesma hierarquia de classes

(ou de um ponteiro do tipo void para qualquer outro ponteiro);

- conversão de um tipo enumerado num tipo inteiro;

- conversão do tipo double num tipo inteiro;

- conversões que podem ser feitas implicitamente (conversão automática entre tipos).

class CData { public: static enum DiaSemana { segunda = 0, terca, quarta, quinta, sexta, sabado, domingo };};

int day = 3;CData::DiaSemana ds = day; //erroCData::DiaSemana ds = static_cast<CData::DiaSemana>(day);

int i = 12345;char c = static_cast<char>(i);

int i = 123; void* vp = &i;fp = static_cast<float*>(vp); // ?

Page 37: Classes bases e derivadas

class Shape { public: virtual ~Shape() {}; };class Circle : public Shape {};class Square : public Shape {};class Other {};

Circle c;Shape* s = &c; // upcasts = static_cast<Shape*>(&c); // upcast explícito

Circle* cp; Square* sp;cp = static_cast<Circle*>(s); // downcast OKsp = static_cast<Square*>(s); // downcast ? Other* op = static_cast<Other*>(s); //erro de compilaçãoOther* op2 = (Other*)s; // não produz erro

Page 38: Classes bases e derivadas

Conversão do tipo base para o tipo derivado chama-se downcasting.

class c2 : public c1....

c1 a; c2 b;

c1* p1 = &b; // upcastingc2* p2 = &a; c2* p2 = (c2*)&a; // ??? downcasting

void* vp;p2 = (c2*)vp; // ???p2->pub_2; // ???

Para efectuar um cast seguro usa-se o operador dynamic_cast.

Este operador recebe uma referência ou um ponteiro para um tipo polimórfico (a classe deve incluir funções virtuais).

Deve ser usado quando a correcção da conversão não pode ser determinada pelo compilador.

c2* p2 = dynamic_cast<c2*>(&a); Questão: O objecto no endereço a é do tipo c2 ?

=

c2& r = dynamic_cast<c2&>(b); Afirmação: O objecto referenciado por b é do tipo c2.

=

dynamic_cast

Page 39: Classes bases e derivadas

window* pw = &w; //upcastwindow_w_caption_and_scroll* pwcs = static_cast<window_w_caption_and_scroll*>(pw);window_w_caption_and_scroll* pwcs = dynamic_cast<window_w_caption_and_scroll*>(pw);

O operador dynamic_cast pode converter uma classe base virtual polimórfica numa classe derivada (downcasting).

O operador static_cast não examina o objecto que converte portanto não pode realizar um downcast quando a classe base é virtual.

dynamic_cast vs. static_cast

O operador dynamic_cast exige um operando polimórfico, enquanto o static_cast não.

Na execução, o operador dynamic_cast é ligeiramente menos eficiente.

O operador dynamic_cast não pode converter um ponteiro do tipo void, enquanto o static_cast pode.

Page 40: Classes bases e derivadas

reinterpret_cast

O operador reinterpret_cast realiza conversões entre tipos não relacionados.

Normalmente, o operador produz valor de um tipo novo composto por mesmos bits que o argumento.

O resultado só é usável se o tipo resultante coincide exactamente com o tipo do argumento.

class X { const int a;public:

X() : a(0) {}friend ostream& operator << (ostream& os, const X& r){ return os << r.a << endl; }

};

X x;cout << x;int* xp = reinterpret_cast<int*>(&x);*xp = 7;cout << *(reinterpret_cast<X*>(xp));cout << x;

este operador deve ser usado com muito cuidado!

Page 41: Classes bases e derivadas

const_cast

O operador const_cast serve para remover os qualificadores const e volatile quando necessário.

const int i = 0;

int* j = &i; // erroint* j = (int*)&i; // sintaxe do C; não aconselhadaj = const_cast<int*>(&i); // esta sintaxe é melhor

volatile int v = 0;int* k = const_cast<int*>(&v);

Page 42: Classes bases e derivadas

Sumário de classes bases e derivadas

1. Em C++ podem ser construídas estruturas hierárquicas nasquais uma classe pode derivar de outra.

2. As relações entre classes base e derivadas são representadasgraficamente, com setas, das classes derivadas para as classes base.

3. A herança traz as seguintes vantagens:permite utilizar o código da classe base sem nenhuma

alteração na classe derivada;permite mutação selectiva. Por exemplo, de uma classe

existente que seja quase o que pretendemos mas não completamente. Ou mesmo a alteração do código de um método da classe base, pois o polimorfismo permite que redefinamos um ou mais métodos.

permite que um método de uma classe base partilhado pelas classes derivadas, seja modificado sem existir a necessidade de reescrever código para cada uma das classes descendentes.

Page 43: Classes bases e derivadas

4. Qualquer classe Derivada pode servir de classe Base. Um conjunto de classes ligado por relações de herança é chamado hierarquia de classes.

5. A um ponteiro para uma classe base pode ser atribuído o valor de um ponteiro para classe derivada sem ser necessária uma conversão explícita (na herança pública).

6. Não é permitido atribuir a um ponteiro para a derivada (pD)um ponteiro para a base (pB) sem uma conversão explícita.

7. Normalmente as classes derivadas são mais poderosas que asclasses base.

8. O controlo do acesso às classes Base e Derivadas é providenciadocom a ajuda dos atributos: private, protected, public.

Page 44: Classes bases e derivadas

9. Os objectos das classes são construídos de cima para baixo :primeiro a base, e depois as classes derivadas. São destruídos naordem inversa.

10. Uma classe que tem pelo menos uma função virtual é chamada classe polimórfica.

11. As funções virtuais permitem construir diferentes versões dasfunções para as classes base e derivadas.

12. Se uma classe base B tiver uma função virtual vf e a classederivada D tiver uma função vf do mesmo tipo, então a chamada de vf por um objecto de D causa a chamada de D::vf mesmo se oacesso seja feito através de um ponteiro ou referência para a classe base.

13. As funções virtuais só podem ser declaradas para classes eestruturas.

Page 45: Classes bases e derivadas

14. Funções virtuais não podem ser estáticas (static).

15. As funções virtuais podem ser declaradas com o especificadorfriend para outras classes.

16. Funções globais não podem ser virtuais.

17. Uma vez definido o método antecessor (na classe Base) comovirtual todos os métodos descendentes com o mesmo nome sãotambém virtuais por defeito.

18. Caso uma função na classe derivada não tenha o mesmo número e tipo de argumentos que a função com o mesmo nome da classe base, esta função não é virtual, mas sim uma função sobrecarregada (function name overloading).

Page 46: Classes bases e derivadas

19. Uma função virtual que seja inicializada a zero é chamada função virtual pura.

20. Uma classe que tem pelo menos uma função virtual pura é chamada classe abstracta.

21. Não é permitido definir objectos de classes abstractas. Logoclasses abstractas podem ser usadas somente como classes basepara outras classes.

22. Se a classe derivada de uma classe base abstracta não implementar as funções virtuais puras que pertencem à classe base, então a classe derivada também é abstracta.

23. Se B é uma classe abstracta então nenhuma função pode receber ou retornar valores do tipo B.

24. É permitido declarar ponteiros para as classes abstractas.

Page 47: Classes bases e derivadas

25. É permitido utilizar referências para classes abstractas.

26. O objectivo principal das classes abstractas é a descrição deinterfaces gerais para as classes derivadas futuras. Neste caso nãoestamos a pensar em detalhes de implementação. A ideia principalé providenciar nomes comuns para funções idênticas em classesdiferentes.

27. Uma classe pode derivar de mais do que uma classe Base. Seusarmos mais do que uma classe Base temos o caso de herançamúltipla.

28. A sequência das classes base na declaração de uma classe derivada só afecta a sequência de chamada dos respectivos construtores e destrutores.

Page 48: Classes bases e derivadas

29. Uma classe não pode ser declarada como classe base maisdo que uma vez directamente.

30. Uma classe pode ser declarada como classe base mais que umavez indirectamente, por exemplo, através das classes derivadasintermédias.

31. De modo a termos certeza que as classes derivadas só têm umaclasse base esta classe base pode ser declarada como virtual.

32. Ao mesmo tempo uma classe derivada pode ter classes basesvirtuais e não virtuais (podem ser herdadas através das classesintermédias).

33. Se um atributo de um componente da classe (base) é public podeser acedido de qualquer lado.

Page 49: Classes bases e derivadas

34. Se um atributo de um componente da classe (base) é protectedsó pode ser acedido por funções da classe e amigos da própria, e por funções e amigos das classes derivadas.

35. Se um atributo de um componente da classe (base) é private sópode ser acedido por funções da classe e os seus amigos.

36. Quando declaramos um ponteiro para a classe base:BASE* ponteiro_para_base;

então este ponteiro dependendo do atributo da classe base pode serpublic, protected ou private. Os componentes da classe base têmdefinidos estes atributos. A classe derivada herda estes atributos daseguinte forma:

se a classe base tem um atributo public, então só oscomponentes public e protected estão acessíveis e terão os mesmosatributos na classe derivada;

Page 50: Classes bases e derivadas

se a classe base tem um atributo protected, então oscomponentes public e protected da classe base tornam-secomponentes protected na classe derivada. Os componentesprivate não estão acessíveis;

se a classe base tem um atributo private, então oscomponentes public e protected da classe base tornam-secomponentes private na classe derivada. Os componentesprivate não estão acessíveisLogo, os atributos da classe base definem só a fronteira superiorde acesso para os seus componentes nas classes derivadas.

37. Os destrutores virtuais permitem chamar o destrutor correctoatravés de um ponteiro para a classe base, mesmo que este ponteiroaponte para uma classe derivada.

38. Se uma classe B tem um destrutor virtual e (BD) então odestrutor de D também será virtual.

Page 51: Classes bases e derivadas

class X{public: virtual void f (int i) { cout << i * i << endl; } virtual void f (char a) { cout << a << endl; } virtual void f (int i, int j) { cout << i * j << endl; }};

class Y : public X{public: void f (int j) { cout << j - 2 << endl; } virtual void g() {}};

X x1;Y y1;

x1.f(5); x1.f('a'); x1.f(2, 3);y1.f(5); y1.f('a'); y1.f(2, 3); y1.g();

X* p = &y1;p->f(5); p->f('a'); p->f(2, 3); p->g();

X& r = x1;r.f(5); r.f('a'); r.f(2, 3);

25 a 63 953 a 625 a 6

É impossível mudar o valor de retorno de uma função virtual quando redefinida na classe derivada!

Se redefinir uma das funções sobrecarregadas da classe base, todas as versões restantes desta função ficam escondidas na classe derivada!