1 / 51

Classes bases e derivadas

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; // ... };.

Download Presentation

Classes bases e derivadas

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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; // ... }; O campo m_pNext é um ponteiro para outro CEmpregado.

  2. Vamos agora definir um gestor. class CGestor { public: CEmpregadom_Proprio; CEmpregado* m_lGrupo; short m_nNivel; // ... }; Um gestor é também um trabalhador. A informação acerca do trabalhador é guardada no campo m_Proprio da classe CGestor. O objectivo é definir um gestor como um trabalhador com alguma informação suplementar: class CGestor : public CEmpregado { public: CEmpregado* m_lGrupo; short m_nNivel; // ... };

  3. A classe CGestor é a classe derivada e a classe CEmpregado é a classe base. 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 uma seta 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 conter empregados ou gestores. Por exemplo:

  4. CGestorg1, g2; CEmpregadoe1, e2; CEmpregado* lista; lista = &g1; // pôr g1 na lista g1.m_pNext = &e1; // pôr e1 na lista e1.m_pNext = &g2; // pôr g2 na lista g2.m_pNext = &e2; // pôr e2 na lista e2.m_pNext = 0; // a lista está terminada Como um gestor é um empregado, o gestor pode ser usado como empregado. Contudo, um empregado não é necessariamente um gestor e por isso empregado não pode ser usado como gestor.

  5. Geralmente se uma classe derivada possuir uma classe base pública então um ponteiro para a classe base pode conter o valor do endereço de um objecto da classe derivada sem ser necessária uma conversão explícita. A conversão oposta, de um ponteiro para a classe base para um ponteiro para a classe derivada, tem de ser explícita. Por exemplo: CGestor g3; CEmpregado* pe = &g3; // Ok CEmpregadoe4; CGestor* pg = &e4; // ERRO: um empregado não é um gestor pg->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 g3 pg->m_nNivel = 2; // Ok: pg é um ponteiro para um gestor que //tem o campo m_nNivel

  6. 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 qual são declarados na classe e destruídos pela ordem inversa.

  7. 1 2 3 4 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) { ... }

  8. Temporario CEmpregado CGestor CSecretario temp_sec CDirector Consultante Uma classe derivada pode também ser base de outras classes. Por exemplo: class CEmpregado{ ... }; class CGestor: public CEmpregado{ ... }; class CDirector : public CGestor{ ... }; A esta relação entre classes chama-se herança. A herança pode ser representada como uma árvore que pode ser mostrada graficamente.

  9. Controlo de acesso Uma classe base pode ser declarada com atributos private, protected e 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).

  10. Herança pública 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*.

  11. OK erro class c2 : public c1 { public: int pub_2; c2() { pub_1; prot_1;priv_1; } protected: int prot_2; private: int priv_2; }; class c1 { public: int pub_1; protected: int prot_1; private: int priv_1; }; 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;

  12. Herança protegida 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*.

  13. OK erro 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 c1 { public: int pub_1; protected: int prot_1; private: int priv_1; }; class c3 : protectedc2 { 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;

  14. Herança privada 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*.

  15. OK erro 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 c1 { public: int pub_1; protected: int prot_1; private: int priv_1; }; class c3 : privatec2 { 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;

  16. public protected private A classe BASE O atributo da classe BASE public: o_membro_público protected: o_membro_protegido private: o_membro_privado A classe DERIVADA O nível superior é público O alto nível é protegido A classe DERIVADA protected: o_membro_público o_membro_protegido ....................................... A classe DERIVADA O alto nível é privado public: o_membro_público protected: o_membro_protegido ....................................... A classe DERIVADA private: o_membro_público o_membro_protegido .......................................

  17. 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.

  18. declaração using Acesso público aos membros privados de uma classe class c2 : private c1 { public: int pub_2; c2() { pub_1;prot_1;priv_1; c1* p = new c2;} using c1::priv_1;// erro using c1::prot_1; using c1::pub_1; protected: int prot_2; private: int priv_2; }; class c1 { public: int pub_1; protected: int prot_1; private: int priv_1; }; 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;

  19. Classe 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 Uma classe é abstracta se esta contém pelo menos uma função virtual pura. Uma função virtual é pura se a sua declaração acaba com “= 0” virtual double Area () = 0; Quando todas as funções de uma classe são virtuais puras, esta chama-se classe abstracta pura.

  20. Heranç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.

  21. Funçõ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.

  22. Destrutores 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.

  23. 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); // ................. };

  24. Herança múltipla A classe derivada pode ter duas (ou mais) classes bases. Neste caso podemos usar a seguinte notação: class DERIVED : public BASE1, public BASE2, ........................ { }; BASE1 BASE2 DERIVED

  25. 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 para as 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 { ... };

  26. 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 window_w _scroll window_w_caption_and_scroll window_w_caption_and_scroll

  27. virtual 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; } Ambiguidade

  28. pessoa pessoa aluno trabalhador aluno_trab

  29. 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(); }; class aluno : public pessoa { public: aluno(string&, unsigned, unsigned); virtual ~aluno(); protected: unsigned turma; }; 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(); };

  30. pessoa pessoa aluno trabalhador aluno_trab int main() { aluno_trab a_t("Pedro", 23, 5135, 180000); a_t.imprimir(); return 0; } void pessoa::imprimir() { cout << "Nome - " << nome << "; Idade - " << idade << endl; } Ambiguidade

  31. 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(); }; class aluno : virtual public pessoa { public: aluno(string&, unsigned, unsigned); virtual ~aluno(); protected: unsigned turma; }; 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(); };

  32. pessoa aluno trabalhador aluno_trab

  33. pessoa aluno trabalhador aluno_trab 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

  34. string string é 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; // stringsvazias string s3 = "Olá"; // stringinicializada string s4("Bom dia"); // stringinicializada s2 = "abc"; // Atribuição de um valor àstring s1 = s3 + " " + s4; // Combinação de strings cout << s1 << endl; return 0; }

  35. 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. reinterpret_cast static_cast dynamic_cast const_cast

  36. 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;//erro CData::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); // ?

  37. class Shape { public: virtual ~Shape() {}; }; class Circle : public Shape {}; class Square : public Shape {}; class Other {}; Circle c; Shape* s = &c; // upcast s = static_cast<Shape*>(&c); // upcast explícito Circle* cp; Square* sp; cp = static_cast<Circle*>(s); // downcast OK sp = static_cast<Square*>(s);// downcast ? Other* op = static_cast<Other*>(s);//erro de compilação Other* op2 = (Other*)s; // não produz erro

  38. dynamic_cast Conversão do tipo base para o tipo derivado chama-se downcasting. class c2 : public c1 .... c1 a; c2 b; c1* p1 = &b; // upcasting c2* 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.

  39. 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 window* pw = &w; //upcast window_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 exige um operando polimórfico, enquanto o static_castnão. Na execução, o operador dynamic_cast é ligeiramente menos eficiente. O operador dynamic_castnão pode converter um ponteiro do tipo void, enquanto o static_castpode.

  40. 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!

  41. const_cast O operador const_cast serve para remover os qualificadores const e volatile quando necessário. const int i = 0; int* j = &i; // erro int* j = (int*)&i; // sintaxe do C; não aconselhada j = const_cast<int*>(&i);// esta sintaxe é melhor volatile int v = 0; int* k = const_cast<int*>(&v);

  42. Sumário de classes bases e derivadas 1. Em C++ podem ser construídas estruturas hierárquicas nas quais uma classe pode derivar de outra. 2. As relações entre classes base e derivadas são representadas graficamente, 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.

  43. 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 as classes base. 8. O controlo do acesso às classes Base e Derivadas é providenciado com a ajuda dos atributos: private, protected, public.

  44. 9. Os objectos das classes são construídos de cimapara baixo : primeiro a base, e depois as classes derivadas. São destruídos na ordem 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 das funções para as classes base e derivadas. 12. Se uma classe base B tiver uma função virtualvf e a classe derivada 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 o acesso 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 e estruturas.

  45. 14. Funções virtuais não podem ser estáticas (static). 15. As funções virtuais podem ser declaradas com o especificador friend para outras classes. 16. Funções globais não podem ser virtuais. 17. Uma vez definido o método antecessor (na classe Base) como virtual todos os métodos descendentes com o mesmo nome são també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).

  46. 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. Logo classes abstractas podem ser usadas somente como classes base para outras classes. 22. Se a classe derivada de uma classe baseabstracta 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.

  47. 25. É permitido utilizar referências para classes abstractas. 26. O objectivo principal das classes abstractas é a descrição de interfaces gerais para as classes derivadas futuras. Neste caso não estamos a pensar em detalhes de implementação. A ideia principal é providenciar nomes comuns para funções idênticas em classes diferentes. 27. Uma classe pode derivar de mais do que uma classe Base. Se usarmos mais do que uma classe Base temos o caso de herança mú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.

  48. 29. Uma classe não pode ser declarada como classe base mais do que uma vez directamente. 30. Uma classe pode ser declarada como classe base mais que uma vez indirectamente, por exemplo, através das classes derivadas intermédias. 31. De modo a termos certeza que as classes derivadas só têm uma classe base esta classe base pode ser declarada como virtual. 32. Ao mesmo tempo uma classe derivada pode ter classes bases virtuais e não virtuais (podem ser herdadas através das classes intermédias). 33. Se um atributo de um componente da classe (base) é public pode ser acedido de qualquer lado.

  49. 34. Se um atributo de um componente da classe (base) é protected só 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 ser public, protected ou private. Os componentes da classe base têm definidos estes atributos. A classe derivada herda estes atributos da seguinte forma: se a classe base tem um atributo public, então só os componentes public e protected estão acessíveis e terão os mesmos atributos na classe derivada;

  50. se a classe base tem um atributo protected, então os componentes public e protected da classe base tornam-se componentes protected na classe derivada. Os componentes private não estão acessíveis; se a classe base tem um atributo private, então os componentes public e protected da classe base tornam-se componentes private na classe derivada. Os componentes private não estão acessíveis Logo, os atributos da classe base definem só a fronteira superior de acesso para os seus componentes nas classes derivadas. 37. Os destrutoresvirtuais permitem chamar o destrutor correcto através de um ponteiro para a classe base, mesmo que este ponteiro aponte para uma classe derivada. 38. Se uma classe B tem um destrutorvirtual e (BD) então o destrutor de D também será virtual.

More Related