Diferença entre inheritance privada, pública e protegida

Qual é a diferença entre inheritance public , private e protected em C ++? Todas as questões que encontrei no SO lidam com casos específicos.

Para responder a essa pergunta, gostaria de descrever os acessadores do membro primeiro com minhas próprias palavras. Se você já sabe disso, pule para o título “next:”.

Existem três accessres que eu conheço: public , protected e private .

Deixei:

 class Base { public: int publicMember; protected: int protectedMember; private: int privateMember; }; 
  • Tudo o que está ciente do Base também está ciente de que Base contém publicMember .
  • Somente as crianças (e seus filhos) sabem que o Base contém protectedMember .
  • Ninguém além do Base está ciente do privateMember .

Por “está ciente de”, quero dizer “reconhecer a existência de, e, portanto, ser capaz de acessar”.

Próximo:

O mesmo acontece com a inheritance pública, privada e protegida. Vamos considerar uma class Base e uma class Child que herda da Base .

  • Se a inheritance for public , tudo o que estiver ciente de Base e Child também está ciente de que Child herda de Base .
  • Se a inheritance estiver protected , somente Child e seus filhos estão cientes de que eles herdam da Base .
  • Se a inheritance for private , ninguém além de Child está ciente da inheritance.
 class A { public: int x; protected: int y; private: int z; }; class B : public A { // x is public // y is protected // z is not accessible from B }; class C : protected A { // x is protected // y is protected // z is not accessible from C }; class D : private A // 'private' is default for classs { // x is private // y is private // z is not accessible from D }; 

NOTA IMPORTANTE: Todas as classs B, C e D contêm as variables ​​x, y e z. É apenas questão de access.

Sobre o uso de inheritance protegida e privada, você pode ler aqui .

Limitar a visibilidade da inheritance fará com que o código não consiga ver que alguma class herda outra class: conversões implícitas do derivado para a base não funcionarão, e static_cast da base para a derivada também não funcionará.

Somente membros / amigos de uma class podem ver inheritance privada, e somente membros / amigos e classs derivadas podem ver inheritance protegida.

inheritance pública

  1. Herança IS-A. Um botão é uma janela, e em qualquer lugar onde uma janela é necessária, um botão pode ser passado também.

     class button : public window { }; 

inheritance protegida

  1. Protegido implementado em termos de. Raramente útil. Usado em boost::compressed_pair para derivar de classs vazias e economizar memory usando otimização de class base vazia (exemplo abaixo não usa template para continuar sendo no ponto):

     struct empty_pair_impl : protected empty_class_1 { non_empty_class_2 second; }; struct pair : private empty_pair_impl { non_empty_class_2 &second() { return this->second; } empty_class_1 &first() { return *this; // notice we return *this! } }; 

inheritance privada

  1. Implementado em termos de. O uso da class base é apenas para implementar a class derivada. Útil com características e se o tamanho é importante (traços vazios que contêm apenas funções usarão a otimização da class base vazia). Muitas vezes a contenção é a melhor solução, no entanto. O tamanho das strings é crítico, por isso é um uso frequentemente visto aqui

     template struct string : private StorageModel { public: void realloc() { // uses inherited function StorageModel::realloc(); } }; 

membro público

  1. Agregar

     class pair { public: First first; Second second; }; 
  2. Accessors

     class window { public: int getWidth() const; }; 

membro protegido

  1. Fornecendo access aprimorado para classs derivadas

     class stack { protected: vector c; }; class window { protected: void registerClass(window_descriptor w); }; 

membro privado

  1. Mantenha os detalhes da implementação

     class window { private: int width; }; 

Observe que os lançamentos no estilo C propositalmente permitem converter uma class derivada em uma class base protegida ou privada de maneira definida e segura e também em outra direção. Isso deve ser evitado a todo custo, porque pode tornar o código dependente dos detalhes da implementação – mas, se necessário, você pode fazer uso dessa técnica.

Tem a ver com como os membros públicos da class base são expostos da class derivada.

  • público -> os membros públicos da class base serão públicos (geralmente o padrão)
  • protected -> os membros públicos da class base serão protegidos
  • private -> os membros públicos da class base serão privados

Como pouco se nota, inheritance pública é inheritance tradicional que você verá na maioria das linguagens de programação. Isto é, modela um relacionamento “IS-A”. Herança privada, algo AFAIK peculiar ao C ++, é um relacionamento “IMPLEMENTADO EM TERMOS DE”. Você quer usar a interface pública na class derivada, mas não quer que o usuário da class derivada tenha access a essa interface. Muitos argumentam que, nesse caso, você deve agregar a class base, ou seja, em vez de ter a class base como uma base privada, faça um membro derivado para reutilizar a funcionalidade da class base.

Essas três palavras-chave também são usadas em um contexto completamente diferente para especificar o modelo de inheritance de visibilidade .

Esta tabela reúne todas as combinações possíveis do modelo de declaração e inheritance do componente, apresentando o access resultante aos componentes quando a subclass é completamente definida.

insira a descrição da imagem aqui

A tabela acima é interpretada da seguinte maneira (dê uma olhada na primeira linha):

se um componente for declarado como público e sua class for herdada como pública, o access resultante será público .

Um exemplo:

  class Super { public: int p; private: int q; protected: int r; }; class Sub : private Super {}; class Subsub : public Sub {}; 

O access resultante para as variables p , q , r na class Subsub é nenhum .

Outro exemplo:

 class Super { private: int x; protected: int y; public: int z; }; class Sub : protected Super {}; 

O access resultante para as variables y , z na class Sub é protegido e para a variável x é nenhum .

Um exemplo mais detalhado:

 class Super { private: int storage; public: void put(int val) { storage = val; } int get(void) { return storage; } }; int main(void) { Super object; object.put(100); object.put(object.get()); cout < < object.get() << endl; return 0; } 

Agora vamos definir uma subclass:

 class Sub : Super { }; int main(void) { Sub object; object.put(100); object.put(object.get()); cout < < object.get() << endl; return 0; } 

A class definida denominada Sub, que é uma subclass de class denominada Super ou essa class Sub é derivada da class Super . A class Sub não introduz novas variables ​​nem novas funções. Isso significa que qualquer object da class Sub herda todas as características após a class Super ser, de fato, uma cópia dos objects de uma Super Classe?

Não Não faz.

Se compilarmos o código a seguir, não obteremos nada além de erros de compilation dizendo que os methods put e get estão inacessíveis. Por quê?

Quando omitimos o especificador de visibilidade, o compilador assume que vamos aplicar a chamada inheritance privada . Isso significa que todos os componentes da superclass pública se transformam em access privado, os componentes da superclass privada não serão acessíveis. Consequentemente, significa que você não tem permissão para usar o último dentro da subclass.

Precisamos informar ao compilador que queremos preservar a política de access usada anteriormente.

 class Sub : public Super { }; 

Não se deixe enganar : isso não significa que os componentes privados da class Super (como a variável de armazenamento) se tornarão públicos de uma forma um tanto mágica. Os componentes privados permanecerão privados , o público permanecerá público .

Objetos da class Sub podem fazer "quase" as mesmas coisas que seus irmãos mais velhos criaram na class Super . "Quase" porque o fato de ser uma subclass também significa que a class perdeu o access aos componentes privados da superclass . Não podemos escrever uma function de membro da Sub class que seria capaz de manipular diretamente a variável de armazenamento.

Esta é uma restrição muito séria. Existe alguma solução?

Sim

O terceiro nível de access é chamado de protegido . A palavra-chave protegida significa que o componente marcado com ela se comporta como um componente público quando usado por qualquer uma das subclasss e se parece com uma privada para o resto do mundo . - Isso é verdade apenas para as classs herdadas publicamente (como a class Super em nosso exemplo) -

 class Super { protected: int storage; public: void put(int val) { storage = val; } int get(void) { return storage; } }; class Sub : public Super { public: void print(void) {cout < < "storage = " << storage;} }; int main(void) { Sub object; object.put(100); object.put(object.get() + 1); object.print(); return 0; } 

Como você vê no código de exemplo nós temos uma nova funcionalidade para a class Sub e isso faz uma coisa importante: ela acessa a variável de armazenamento da class Super .

Não seria possível se a variável fosse declarada como privada. No escopo da function principal, a variável permanece oculta, assim, se você escrever algo como:

 object.storage = 0; 

O compilador irá informá-lo que é um error: 'int Super::storage' is protected .

Finalmente, o último programa produzirá a seguinte saída:

 storage = 101 
 Member in base class : Private Protected Public 

Tipo de inheritance : object herdado como :

 Private : Inaccessible Private Private Protected : Inaccessible Protected Protected Public : Inaccessible Protected Public 

1) Herança Pública :

uma. Membros privados da class Base não são acessíveis na class Derived.

b. Membros protegidos da class Base permanecem protegidos na class Derived.

c. Membros públicos da class Base permanecem públicos na class Derived.

Assim, outras classs podem usar membros públicos da class Base através do object de class Derived.

2) Herança Protegida :

uma. Membros privados da class Base não são acessíveis na class Derived.

b. Membros protegidos da class Base permanecem protegidos na class Derived.

c. Membros públicos da class Base também se tornam membros protegidos da class Derived.

Assim, outras classs não podem usar membros públicos da class Base através do object de class Derived; mas estão disponíveis para a subclass de Derived.

3) Herança Privada :

uma. Membros privados da class Base não são acessíveis na class Derived.

b. Membros protegidos e públicos da class Base tornam-se membros privados da class Derived.

Portanto, nenhum membro da class Base pode ser acessado por outras classs através do object de class Derived, pois elas são privadas na class Derived. Portanto, mesmo a subclass da class Derived não pode acessá-los.

Herança pública modela um relacionamento IS-A. Com

 class B {}; class D : public B {}; 

todo D é um B

Modelos de inheritance privada um relacionamento IS-IMPLEMENTE-USING (ou o que quer que seja chamado). Com

 class B {}; class D : private B {}; 

um D não é um B , mas todo D usa seu B em sua implementação. Herança privada sempre pode ser eliminada usando confinamento em vez disso:

 class B {}; class D { private: B b_; }; 

Este D também pode ser implementado usando B , neste caso usando seu b_ . A contenção é um acoplamento menos rígido entre os tipos do que a inheritance, portanto, em geral, deve ser preferível. Às vezes, usar a contenção em vez da inheritance privada não é tão conveniente quanto a inheritance privada. Muitas vezes essa é uma desculpa tola para ser preguiçoso.

Eu não acho que alguém sabe o que protected modelos de inheritance. Pelo menos eu não vi nenhuma explicação convincente ainda.

Se você herdar publicamente de outra class, todo mundo sabe que você está herdando e você pode ser usado polimorficamente por qualquer pessoa através de um ponteiro de class base.

Se você herdar de forma protegida, somente as classs de seus filhos poderão usá-lo polimorficamente.

Se você herdar de maneira privada, somente você poderá executar methods de class pai.

O que basicamente simboliza o conhecimento que o resto das classs tem sobre seu relacionamento com sua class pai

Membros de dados protegidos podem ser acessados ​​por qualquer class que herda da sua class. Membros de dados privados, no entanto, não podem. Vamos supor que temos o seguinte:

 class MyClass { private: int myPrivateMember; // lol protected: int myProtectedMember; }; 

De dentro de sua extensão para esta class, referenciar this.myPrivateMember não funcionará. No entanto, this.myProtectedMember irá. O valor ainda é encapsulado, portanto, se tivermos uma instanciação dessa class chamada myObj , então myObj.myProtectedMember não funcionará, portanto, é semelhante em function a um membro de dados privados.

Resumo:

  • Privado: ninguém pode ver, exceto dentro da class
  • Protegido: classs derivadas + particulares podem vê-lo
  • Público: o mundo pode ver

Ao herdar, você pode (em alguns idiomas) alterar o tipo de proteção de um membro de dados em determinada direção, por exemplo, de protegido para público.

 Accessors | Base Class | Derived Class | World —————————————+————————————+———————————————+——————— public | y | y | y —————————————+————————————+———————————————+——————— protected | y | y | n —————————————+————————————+———————————————+——————— private | | | or | y | n | n no accessor | | | y: accessible n: not accessible 

Baseado neste exemplo para java … acho que uma pequena mesa vale mais que mil palavras 🙂

Privado:

Os membros privados de uma class base só podem ser acessados ​​por membros dessa class base.

Público:

Os membros públicos de uma class base podem ser acessados ​​por membros dessa class base, membros de sua class derivada, bem como os membros que estão fora da class base e da class derivada.

Protegido:

Os membros protegidos de uma class base podem ser acessados ​​por membros da class base, bem como por membros de sua class derivada.


Em resumo:

privado : base

protegido : base + derivado

public : base + derived + qualquer outro membro

Eu encontrei uma resposta fácil e pensei em postá-lo para a minha referência futura também.

É dos links http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

 class Base { public: int m_nPublic; // can be accessed by anybody private: int m_nPrivate; // can only be accessed by Base member functions (but not derived classs) protected: int m_nProtected; // can be accessed by Base member functions, or derived classs. }; class Derived: public Base { public: Derived() { // Derived's access to Base members is not influenced by the type of inheritance used, // so the following is always true: m_nPublic = 1; // allowed: can access public base members from derived class m_nPrivate = 2; // not allowed: can not access private base members from derived class m_nProtected = 3; // allowed: can access protected base members from derived class } }; int main() { Base cBase; cBase.m_nPublic = 1; // allowed: can access public members from outside class cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class } 

É essencialmente a proteção de access dos membros públicos e protegidos da class base na class derivada. Com inheritance pública, a class derivada pode ver membros públicos e protegidos da base. Com inheritance privada, não pode. Com protected, a class derivada e quaisquer classs derivadas dela podem vê-las.