Níveis de Acesso na Herança
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 49 de 104.
O tipo de herança que você escolhe afeta como os membros da classe base são acessados na classe derivada. O C++ oferece três opções: herança public, protected e private.
Veja como cada tipo transforma o `access` do membro:
| Membro `Base` | `inheritance` pública | `inheritance` protegida | `inheritance` privada |
|---|---|---|---|
| `public` | `public` | `protected` | `private` |
| `protected` | `protected` | `protected` | `private` |
| `private` | `inaccessible` | `inaccessible` | `inaccessible` |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub é public, prot é protected, priv é inacessível
};
class ProtectedDerived : protected Base {
// pub é protected, prot é protected, priv é inacessível
};
class PrivateDerived : private Base {
// pub é private, prot é private, priv é inacessível
};Herança pública (Public inheritance) modela relações "é-um" e é de longe a mais comum. Um Dog é um Animal, portanto, o código externo pode tratá-lo como tal.
A inheritance protected e private model relações "implementado-em-termos-de". Elas ocultam a interface da base class do código externo, útil quando você deseja reutilizar a implementação sem expor o relacionamento de inheritance. Com private inheritance, até mesmo classes derived adicionais perdem access aos membros base originais.
Desafio
FácilVamos explorar como diferentes tipos de herança afetam a acessibilidade dos membros construindo uma hierarquia simples de dispositivos. Você criará uma classe base Device e três classes derivadas, cada uma usando um tipo de herança diferente, para ver em primeira mão como a herança pública, protegida e privada transforma o acesso aos membros.
Você organizará seu código em dois arquivos:
Device.h: Defina uma classe baseDevicecom três membros em diferentes níveis de acesso:- Um
std::string modelpúblico - Um
int serialNumberprotegido - Um
int internalCodeprivado (definido como 999 por padrão) - Um método público
showModel()que imprime:Model: <model>
Em seguida, crie três classes derivadas que herdam de
Deviceusando diferentes tipos de herança:PublicDeviceusando herança pública — adicione um métododisplaySerial()que imprime:Serial: <serialNumber>ProtectedDeviceusando herança protegida — adicione um métododisplaySerial()que imprime:Serial: <serialNumber>PrivateDeviceusando herança privada — adicione um métododisplaySerial()que imprime:Serial: <serialNumber>
Cada classe derivada deve ter um construtor que aceita um nome de modelo e um número de série, passando o modelo para a classe base e definindo o número de série.
- Um
main.cpp: Leia duas entradas (cada uma em uma linha separada):- Nome do modelo (string)
- Número de série (inteiro)
Crie um objeto de cada tipo derivado com os mesmos valores de entrada. Em seguida, demonstre as diferenças de acesso:
Para
PublicDevice:- Chame
showModel()diretamente no objeto (funciona porque a herança pública o mantém público) - Acesse
modeldiretamente e imprima:Direct model access: <model> - Chame
displaySerial()
Para
ProtectedDeviceePrivateDevice:- Apenas chame
displaySerial()(os membros herdadosshowModel()emodelnão são mais acessíveis publicamente do lado de fora)
Formato de saída:
--- PublicDevice --- Model: <model> Direct model access: <model> Serial: <serial> --- ProtectedDevice --- Serial: <serial> --- PrivateDevice --- Serial: <serial>
Por exemplo, com as entradas Laptop e 12345:
--- PublicDevice ---
Model: Laptop
Direct model access: Laptop
Serial: 12345
--- ProtectedDevice ---
Serial: 12345
--- PrivateDevice ---
Serial: 12345Observe como apenas PublicDevice permite acesso externo aos membros públicos herdados. Os outros tipos de herança ocultam a interface da classe base do código externo, mas as classes derivadas ainda podem acessar membros protegidos internamente por meio de seus próprios métodos.
Experimente você mesmo
#include <iostream>
#include <string>
#include "Device.h"
using namespace std;
int main() {
// Ler entrada
string modelName;
int serialNum;
getline(cin, modelName);
cin >> serialNum;
// TODO: Crie objetos de cada tipo derivado com os valores de entrada
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Demonstrate PublicDevice access
cout << "--- PublicDevice ---" << endl;
// - Chame showModel() diretamente no objeto
// - Access model directly and print: Direct model access: <model>
// - Chame displaySerial()
// TODO: Demonstrate ProtectedDevice access
cout << "--- ProtectedDevice ---" << endl;
// - Chame apenas displaySerial() (showModel e model não são acessíveis publicamente)
// TODO: Demonstrate PrivateDevice access
cout << "--- PrivateDevice ---" << endl;
// - Chame apenas displaySerial() (showModel e model não são acessíveis publicamente)
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico