Especificadores de Acesso em Detalhes
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 35 de 104.
Agora que você entende os três especificadores de acesso, vamos explorar como eles se comportam quando você tem múltiplos objetos da mesma classe. Um equívoco comum é que private significa "apenas este objeto" - mas, na verdade, significa "apenas esta classe".
Objetos da mesma classe podem acessar os membros privados uns dos outros:
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Acessando o membro privado de outro objeto - permitido!
std::cout << other.secret;
}
};Isso funciona porque o controle de acesso é aplicado no nível da classe, não no nível do objeto. O método readSecret faz parte da classe Person, portanto, ele pode acessar membros privados de qualquer objeto Person. Esse design permite que operações como construtores de cópia e operadores de comparação trabalhem com o estado interno de outros objetos.
Você também pode alternar entre especificadores de acesso várias vezes dentro de uma classe:
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // De volta para public
private:
void privateHelper(); // Privado novamente
};Embora isso seja C++ válido, geralmente é melhor agrupar os membros por nível de acesso para fins de legibilidade. A maioria dos guias de estilo recomenda listar os membros públicos primeiro (já que eles formam a interface da classe), seguidos pelos protegidos e, depois, pelos privados.
Desafio
FácilVamos construir um sistema de comparação de carteiras que demonstra como objetos da mesma classe podem acessar os membros privados uns dos outros. Este é um insight fundamental sobre o controle de acesso em C++ — ele é aplicado no nível da classe, não no nível do objeto.
Você criará dois arquivos para organizar seu código:
Wallet.h: Defina uma classeWalletque armazena dados financeiros privados, mas permite comparações entre carteiras. Sua classe deve ter:- Membros privados:
ownerName(string) ebalance(double) - Um construtor que recebe o nome do proprietário e o saldo inicial
- Um getter público
getOwnerName()que retorna o nome do proprietário - Um método
hasMoreThan(const Wallet& other)que compara o saldo desta carteira com o saldo privado de outra carteira, retornandotruese esta carteira tiver mais dinheiro - Um método
combinedBalance(const Wallet& other)que retorna a soma dos saldos privados de ambas as carteiras - Um método
transferTo(Wallet& other, double amount)que move dinheiro desta carteira para outra — ele deve modificar diretamente os saldos privados de ambas as carteiras (apenas se o valor for positivo e não exceder o saldo desta carteira)
- Membros privados:
main.cpp: Demonstre o acesso a membros privados entre objetos. Leia dois nomes de proprietários e dois saldos da entrada (quatro linhas: name1, balance1, name2, balance2) e, em seguida:- Crie dois objetos
Walletcom os valores de entrada - Imprima
"Combined wealth: "Combined wealth: $usando"lt;amount>" combinedBalance() - Compare as carteiras e imprima
"<name> has more money"para o proprietário que tiver o saldo maior (usehasMoreThan()para determinar isso) - Transfira
100.0da primeira carteira para a segunda usandotransferTo() - Imprima
"After transfer:" - Imprima
"Combined wealth: "Combined wealth: $novamente (deve permanecer inalterado)"lt;amount>" - Compare novamente e imprima
"<name> has more money"(o resultado pode ter mudado)
- Crie dois objetos
O conceito principal aqui é que métodos como hasMoreThan() e transferTo() podem acessar diretamente o membro privado balance de outro objeto Wallet — sem a necessidade de getters. Isso funciona porque o controle de acesso em C++ é baseado em classe: qualquer código dentro da classe Wallet pode acessar membros privados de qualquer objeto Wallet.
Formate todos os valores monetários com duas casas decimais usando std::fixed e std::setprecision(2) de <iomanip>. Converta as entradas de saldo usando std::stod().
Folha de consulta
O controle de acesso em C++ é aplicado no nível da classe, não no nível do objeto. Isso significa que objetos da mesma classe podem acessar os membros privados uns dos outros:
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Acessando o membro privado de outro objeto - permitido!
std::cout << other.secret;
}
};O método readSecret pode acessar o membro privado secret de qualquer objeto Person porque ele faz parte da classe Person. Esse design permite operações como construtores de cópia e operadores de comparação.
Você pode alternar entre especificadores de acesso várias vezes dentro de uma classe:
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // De volta para public
private:
void privateHelper(); // Privado novamente
};No entanto, é uma prática melhor agrupar os membros por nível de acesso para facilitar a leitura. A maioria dos guias de estilo recomenda listar os membros públicos primeiro, seguidos pelos protegidos e, depois, pelos privados.
Experimente você mesmo
#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"
using namespace std;
int main() {
// Ler entrada: name1, balance1, name2, balance2
string name1, name2;
string balanceStr1, balanceStr2;
getline(cin, name1);
getline(cin, balanceStr1);
getline(cin, name2);
getline(cin, balanceStr2);
double balance1 = stod(balanceStr1);
double balance2 = stod(balanceStr2);
// Configurar a formatação de saída para valores monetários
cout << fixed << setprecision(2);
// TODO: Criar dois objetos Wallet com os valores de entrada
// TODO: Imprimir a riqueza combinada usando combinedBalance()
// Formato: "Combined wealth: $<amount>"
// TODO: Comparar as carteiras usando hasMoreThan() e imprimir quem tem mais dinheiro
// Formato: "<name> has more money"
// TODO: Transferir 100.0 da primeira carteira para a segunda usando transferTo()
// TODO: Imprimir "After transfer:"
// TODO: Imprimir a riqueza combinada novamente
// TODO: Comparar novamente e imprimir quem tem mais dinheiro
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