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 acesso aos membros:
| Membro Base | herança public | herança protected | herança private |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | inacessível | inacessível | inacessível |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub é público, prot é protegido, priv é inacessível
};
class ProtectedDerived : protected Base {
// pub é protegido, prot é protegido, priv é inacessível
};
class PrivateDerived : private Base {
// pub é privado, prot é privado, priv é inacessível
};Herança pública modela relacionamentos "é-um" e é de longe a mais comum. Um Dog é um Animal, então o código externo pode tratá-lo como tal.
Herança protegida e privada modelam relacionamentos do tipo "implementado-em-termos-de". Elas escondem a interface da classe base do código externo, o que é útil quando você deseja reutilizar a implementação sem expor o relacionamento de herança. Com a herança privada, até mesmo classes derivadas subsequentes perdem o acesso aos membros originais da base.
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 receba 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:- Chame apenas
displaySerial()(os membros herdadosshowModel()emodelnão são mais acessíveis publicamente pelo 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 o 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.
Folha de consulta
O C++ oferece três tipos de herança que controlam como os membros da classe base são acessados nas classes derivadas:
| Membro da Base | herança pública | herança protegida | herança privada |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | inacessível | inacessível | inacessível |
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
};A herança pública modela relacionamentos do tipo "é-um" (is-a) e é a mais comum. O código externo pode acessar membros públicos da classe base por meio da classe derivada.
A herança protegida e privada modelam relacionamentos do tipo "implementado-em-termos-de" (implemented-in-terms-of). Elas escondem a interface da classe base do código externo. Com a herança privada, até mesmo classes derivadas posteriormente perdem o acesso aos membros originais da base.
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: Criar objetos de cada tipo derivado com os valores de entrada
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Demonstrar o acesso a PublicDevice
cout << "--- PublicDevice ---" << endl;
// - Chamar showModel() diretamente no objeto
// - Acessar model diretamente e imprimir: Direct model access: <model>
// - Chamar displaySerial()
// TODO: Demonstrar o acesso a ProtectedDevice
cout << "--- ProtectedDevice ---" << endl;
// - Chamar apenas displaySerial() (showModel e model não são acessíveis publicamente)
// TODO: Demonstrar o acesso a PrivateDevice
cout << "--- PrivateDevice ---" << endl;
// - Chamar 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