Menu

Especificadores de acesso em C++: public, private, protected

Como public, private e protected controlam quem pode mexer nos membros de uma classe em C++ - a base do encapsulamento, com getters, setters e a saída de emergência friend.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Quem pode mexer nos seus dados

Quando você escreveu sua primeira classe, provavelmente expôs todos os membros ao mundo externo. Isso funciona, mas joga fora um dos principais motivos pelos quais as classes existem: o encapsulamento - ocultar o estado interno de uma classe para que o resto do programa só possa interagir com ela por meio de uma superfície controlada. Os especificadores de acesso são como você traça essa fronteira.

Há exatamente três: public, private e protected. Cada um rotula os membros que vêm depois dele, e o rótulo decide qual código pode lê-los ou escrevê-los. Acerte isso e sua classe impõe as próprias regras; erre e qualquer bug em qualquer lugar pode corromper o estado do seu objeto.

Os três especificadores

Um especificador é uma palavra-chave seguida de dois pontos. Todo membro declarado depois dele - até o próximo especificador - fica sob aquele nível de acesso.

Descomente a última linha e o compilador se recusa a construir: balance é private, então main não pode mexer nele diretamente. É esse o objetivo - a única forma de alterar o saldo é por meio de deposit, o que significa que você pode depois adicionar validação (sem depósitos negativos, registro, limites) em um único lugar e confiar que ela é sempre aplicada.

Aqui está o detalhamento completo:

//             acessível de...
// public      qualquer lugar (qualquer código que tenha o objeto)
// private     só os membros da própria classe (+ friends)
// protected   os membros da própria classe E as classes derivadas (+ friends)

class versus struct: o padrão

Você pode escrever quantos blocos de especificadores quiser, em qualquer ordem. O que os membros recebem antes de você escrever o primeiro depende de você ter usado class ou struct:

  • Em uma class, os membros são private por padrão.
  • Em um struct, os membros são public por padrão.

Esse padrão é a única diferença em nível de linguagem entre as duas palavras-chave. Um struct pode ter métodos, construtores e seções private exatamente como uma class.

A convenção é usar struct para meros agrupamentos de dados públicos e class quando você quer comportamento e estado oculto - mas o compilador não impõe isso, só o padrão difere.

Encapsulamento com getters e setters

O padrão do dia a dia é: os dados vão para uma seção private e um método public dá acesso controlado. Um getter somente leitura retorna o valor; um setter valida antes de atribuir. É aqui que private compensa.

Como celsius é private, não há como infiltrar um valor inválido - toda escrita precisa passar por setCelsius, que protege a invariante. Repare que os getters estão marcados como const: eles prometem não modificar o objeto, então você também pode chamá-los em objetos const Temperature.

protected e a herança

protected só importa quando a herança entra em cena. Ele se comporta como private para o código externo, mas uma classe derivada pode acessá-lo. Use-o para membros que uma subclasse legitimamente precisa, mas que o público ainda não deveria ter.

Um erro comum de iniciante é recorrer a protected em todo membro de dados "por via das dúvidas, caso uma subclasse precise". Isso amplia silenciosamente o contrato da sua classe - agora cada subclasse pode depender daquele campo e você não pode alterá-lo livremente. Prefira private e só promova para protected quando uma classe derivada genuinamente precisar do acesso.

A saída de emergência friend

Às vezes uma única função ou classe externa legitimamente precisa enxergar suas entranhas - um caso clássico é um operador como << que você não pode tornar membro. A palavra-chave friend concede a essa única entidade nomeada acesso aos seus membros private e protected, e a nada mais.

friend é uma exceção deliberada e cirúrgica - a própria classe nomeia exatamente em quem confia, de modo que ninguém pode se conceder acesso de fora. Use-o com parcimônia; se você se pega adicionando muitos friends, provavelmente seus membros não deveriam ter sido private para começar, ou seu projeto precisa ser repensado.

Erros comuns a evitar

  • Tornar todos os membros public. Parece fácil, mas você perde toda a validação e as invariantes que o encapsulamento traz. Por padrão, dados private com métodos public.
  • Esquecer o padrão de class. class Foo { int x; }; torna x private, então foo.x = 5 não vai compilar. Se você queria um simples agrupamento de dados, use struct ou adicione um rótulo public:.
  • Abusar de protected. É uma fronteira mais fraca que private e só é relevante com herança. Recorrer a ele em todo lugar acopla as subclasses a campos que você talvez queira mudar.
  • Esperar que private seja um recurso de segurança. É uma regra de tempo de compilação que evita acesso acidental, não criptografia. Os bytes continuam na memória; private é sobre design limpo, não sobre sigilo.

Próximo: Structs

Você já viu que um struct é, na verdade, apenas uma class cujos membros são public por padrão. A próxima página, structs, aprofunda quando esse padrão público-por-padrão é exatamente o que você quer - agregados leves para agrupar valores relacionados - e como o struct é usado no C++ idiomático ao lado de classes completas.

Perguntas frequentes

Qual é a diferença entre public, private e protected em C++?

Membros public são acessíveis de qualquer lugar. Membros private só são acessíveis de dentro da própria classe (e de seus friends). protected é como private, mas também permite que classes derivadas acessem o membro. Por convenção, você mantém os dados private e expõe o comportamento por meio de métodos public.

Os membros são privados por padrão em C++?

Em uma class, sim - tudo é private até você escrever um especificador de acesso. Em um struct, o padrão é public. Esse único padrão é a verdadeira diferença entre class e struct em C++; ambos podem ter métodos, construtores e especificadores de acesso.

O que a palavra-chave friend faz em C++?

friend concede a uma função ou classe específica acesso aos seus membros private e protected. É uma exceção deliberada e restrita ao encapsulamento - a classe nomeia exatamente em quem confia, de modo que o acesso nunca é concedido implicitamente.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR