Membros privados e protegidos: C ++

276

Alguém pode me esclarecer sobre a diferença entre privatee os protectedmembros das classes?

Eu entendo de melhores convenções de prática que as variáveis e funções que não são chamados de fora da classe deve ser feita private- mas olhando para o meu MFC projecto, MFC parece favor protected.

Qual é a diferença e qual devo usar?

Konrad
fonte

Respostas:

374

Membros privados são acessíveis apenas dentro da classe que os define.

Os membros protegidos são acessíveis na classe que os define e nas classes que herdam dessa classe.

Editar: Ambos também são acessíveis por amigos de sua classe e, no caso de membros protegidos, por amigos de suas classes derivadas.

Editar 2: use o que fizer sentido no contexto do seu problema. Você deve tentar tornar os membros privados sempre que puder reduzir o acoplamento e proteger a implementação da classe base, mas se isso não for possível, use membros protegidos. Verifique as Perguntas frequentes sobre C ++ para entender melhor o problema. Esta pergunta sobre variáveis ​​protegidas também pode ajudar.

Firas Assaad
fonte
12
O link para o C ++ FAQ Lite foi movido para isocpp.org/wiki/faq/basics-of-inheritance
avner
134

Os membros públicos de uma classe A são acessíveis a todos e a todos.

Membros protegidos de uma classe A não são acessíveis fora do código de A, mas são acessíveis a partir do código de qualquer classe derivada de A.

Membros particulares de uma classe A não são acessíveis fora do código de A ou do código de qualquer classe derivada de A.

Portanto, no final, escolher entre protegido ou privado está respondendo às seguintes perguntas: Quanta confiança você deseja depositar no programador da classe derivada?

Por padrão , suponha que a classe derivada não seja confiável e torne seus membros privados . Se você tiver um bom motivo para conceder acesso gratuito dos componentes internos da classe mãe às classes derivadas, poderá protegê-las.

paercebal
fonte
A classe derivada deve ser um tipo da sua classe e os dados protegidos da classe base fazem parte dos dados da classe derivada. Espera-se que o gravador da classe derivada manipule esses dados corretamente ou é um bug. Dados privados em uma classe base são, no entanto, algo que o gravador da classe derivada não controla.
CashCow
@CashCow the protected data of the base class is part of the data of the derived class.De fato. Não é melhor, então, fazer o escritor da classe derivada declarar que os dados em sua classe, em vez dos meus? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.No padrão NVI, o objetivo é tornar tudo privado, incluindo métodos, para limitar o dano que o gravador de classe derivada poderia causar à hierarquia. Métodos protegidos já são um problema em potencial. Não estou convencido de que agravar isso usando o estado protegido seja a abordagem correta.
paercebal
Pode ser, o que exigiria que você tivesse "getters" virtuais na classe base para acessá-lo. E embora você possa ter aulas intermediárias para fazer as diferentes maneiras em que o padrão de dados pode ser implementado, nem sempre é prático fazê-lo. Por exemplo, um "padrão", comum em linguagens que não possui um modificador "const", embora não seja necessário na maioria das vezes no C ++, é ter uma classe base somente leitura e classes derivadas graváveis. No C ++, isso também pode ser bom, simplesmente porque você deseja mais de uma maneira possível de carregar (inicializar) os dados.
Cashcow
Existem várias maneiras de fazer isso. Faça suas classes de serialização amigos. Coloque todos os seus dados em uma estrutura com acesso público, mas sua classe possui um membro privado dessa variável ... Membros protegidos e classes derivadas para carregá-los de qualquer fonte às vezes mais fácil.
CashCow
63

Membros protegidos podem ser acessados ​​a partir de classes derivadas. Os privados não podem.

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

Em termos de "melhores práticas", isso depende. Se houver uma fraca possibilidade de alguém querer derivar uma nova classe da sua e já precisar de acesso a membros internos, torne-os Protegidos, não Privados. Se eles são particulares, sua classe pode se tornar difícil de herdar facilmente.

Roddy
fonte
3
Eu imploro para diferir: se houver uma fraca possibilidade de que nenhuma subclasse precise, torne-a privada. A menos que você pretenda ter sua classe subclassificada, use o padrão do método de modelo.
Xtofl 22/10/08
23

A razão pela qual o MFC favorece a proteção é porque é uma estrutura. Você provavelmente deseja subclassificar as classes MFC e, nesse caso, é necessária uma interface protegida para acessar métodos que não são visíveis para o uso geral da classe.

Toon Krijthe
fonte
9

Tudo depende do que você deseja fazer e do que você deseja que as classes derivadas possam ver.

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}
Mats Fredriksson
fonte
6

Os atributos e métodos marcados como protectedsão - ao contrário dos privados - ainda são visíveis nas subclasses.

A menos que você não queira usar ou fornecer a possibilidade de substituir o método em possíveis subclasses, eu o faria private.

fhe
fonte
2
Uma classe derivada pode substituir as funções virtuais privadas da sua base de
James Hopkin
6

Certamente, dê uma olhada na pergunta Variáveis ​​de membro protegido . É recomendável usar privado como padrão (assim como o C ++ classses) para reduzir o acoplamento. As variáveis ​​de membro protegidas são sempre uma péssima idéia; as funções de membro protegidas podem ser usadas, por exemplo, no padrão Template Method.

xtofl
fonte
Engraçado, editei isso no meu post antes de ver o seu. Upvoted porque as aves de um tropeço pena sobre o mesmo link :)
Firas Assaad
4

Membros protegidos podem ser acessados ​​apenas por descendentes da classe e por código no mesmo módulo. Os membros privados podem ser acessados ​​apenas pela classe em que estão declarados e pelo código no mesmo módulo.

É claro que as funções de amigos jogam isso pela janela, mas tudo bem.

Ignacio Vazquez-Abrams
fonte
4

membros privados são acessíveis apenas dentro da classe, membros protegidos são acessíveis na classe e nas classes derivadas. É um recurso de herança em idiomas OO.

Você pode ter herança pública, protegida e pública em C ++, que determinará quais classes derivadas podem acessar na hierarquia de herança. C #, por exemplo, tem apenas herança pública.

PhilGriffin
fonte
3

privado = acessível somente pela nave-mãe (classe base) (ou seja, apenas meus pais podem entrar no quarto dos meus pais)

protected = acessível pela nave-mãe (classe base) e suas filhas (ou seja, apenas meus pais podem entrar no quarto dos meus pais, mas deram permissão ao filho) para entrar no quarto dos pais)

público = acessível por nave-mãe (classe base), filha e todos os outros (ou seja, apenas meus pais podem entrar no quarto dos meus pais, mas é uma festa em casa - mi casa su casa)

Johan K. Rhodes
fonte
2

Como nenhuma função pública de membro é necessária para buscar e atualizar membros protegidos na classe derivada, isso aumenta a eficiência do código e reduz a quantidade de código que precisamos escrever. No entanto, o programador da classe derivada deve estar ciente do que está fazendo.

nulo
fonte
Você sempre pode usar uma função embutida implementada na declaração de classe. O compilador otimizará isso (e isso seria uma boa maneira de impor o acesso somente leitura a uma variável membro privada, por exemplo).
Paul Sanders
2

privateé preferido para dados do membro. Os membros nas classes C ++ são privatepor padrão.

publicé preferido para funções-membro, embora seja uma questão de opinião. Pelo menos alguns métodos devem estar acessíveis. publicé acessível a todos. É a opção mais flexível e menos segura. Qualquer um pode usá-los e qualquer pessoa pode usá-los mal.

privatenão é acessível. Ninguém pode usá-los fora da classe e ninguém pode usá-los mal. Nem mesmo em classes derivadas.

protectedé um compromisso porque pode ser usado em classes derivadas. Ao derivar de uma classe, você tem um bom entendimento da classe base e toma cuidado para não abusar desses membros.

MFC é um wrapper C ++ para API do Windows, ele prefere publice protected. Classes geradas pelo Visual Studio Assistente de ter um mix feio protected, publice privatemembros. Mas há alguma lógica nas próprias classes do MFC.

Membros como SetWindowTextsão publicporque você geralmente precisa acessar esses membros.

Membros como OnLButtonDown, manipulam as notificações recebidas pela janela. Eles não devem ser acessados, pois são protected. Você ainda pode acessá-los na classe derivada para substituir essas funções.

Alguns membros precisam fazer threads e loops de mensagens, eles não devem ser acessados ​​ou substituir, portanto, são declarados como private

Nas estruturas C ++, os membros são publicpor padrão. As estruturas são geralmente usadas apenas para dados, não para métodos; portanto, a publicdeclaração é considerada segura.

Barmak Shemirani
fonte
1
Você escreve "Membros em classes C ++ são protegidos por padrão". De acordo com o padrão, eles são privados ou públicos por padrão, dependendo da palavra-chave usada na definição (14p3). A Microsoft se desvia do padrão aqui?
Alexander Klauer 8/08/19
@AlexanderKlauer Eu estava errado, é privatepor padrão no Visual Studio. Por privatepadrão, também está no gcc, nunca publicpor padrão. A menos que eu esteja errado de novo. Não consigo encontrar o padrão a que você está se referindo.
Barmak Shemirani
Desculpe, eu deveria ter sido mais específico. Eu estava me referindo ao padrão C ++ 17. O padrão C ++ 11 tem a mesma redação em 11p3. Você poderia atualizar sua resposta? Obrigado!
Alexander Klauer 8/08/19
1

O membro privado pode ser acessado apenas na mesma classe em que declarou onde, como membro protegido, pode ser acessado na classe em que é declarado, juntamente com as classes que são herdadas por ele.

Gayki
fonte
1
  • Privado : é um especificador de acesso. Por padrão, as variáveis ​​de instância (membro) ou os métodos de uma classe em c ++ / java são privados. Durante a herança, o código e os dados são sempre herdados, mas não são acessíveis fora da classe. Podemos declarar nossos membros de dados como privados, para que ninguém possa fazer alterações diretas em nossas variáveis ​​de membro e possamos fornecer getters e setters públicos para alterar nossos membros privados. E esse conceito é sempre aplicado na regra de negócios.

  • Protegido : também é um especificador de acesso. No C ++, os membros protegidos são acessíveis na classe e na classe herdada, mas não fora da classe. Em Java, os membros protegidos são acessíveis dentro da classe, tanto para a classe herdada quanto para todas as classes dentro do mesmo pacote.

Tutu Kumari
fonte
0

Um membro da classe base não estático protegido pode ser acessado por membros e amigos de qualquer classe derivada dessa classe base, usando um dos seguintes:

  • Um ponteiro para uma classe derivada direta ou indiretamente
  • Uma referência a uma classe derivada direta ou indiretamente
  • Um objeto de uma classe derivada direta ou indiretamente
mujtaba
fonte
0

Privado : acessível por funções de membro da classe e função de amigo ou classe de amigo. Para a classe C ++, esse é o especificador de acesso padrão.

Protegido: acessível por funções de membro da classe, função de amigo ou classe de amigo e classes derivadas.

  • Você pode manter a variável ou função de membro da classe (mesmo typedefs ou classes internas) como privada ou protegida conforme sua exigência.
  • Na maioria das vezes, você mantém os alunos como privados e adiciona funções get / set para encapsular. Isso ajuda na manutenção do código.
  • Geralmente, a função privada é usada quando você deseja manter as funções públicas modulares ou eliminar o código repetido em vez de gravar o código inteiro na função única. Isso ajuda na manutenção do código.

Consulte este link para mais detalhes.

Darshan Rajgor
fonte
-2

Os modificadores de acesso privado e protegido são a mesma coisa que membros protegidos da classe base podem ser acessados ​​fora do escopo da classe base na classe filho (derivada). Também se aplica o mesmo à herança. Mas com o modificador privado, os membros da classe base só podem ser acessados ​​no escopo ou código da classe base e suas funções de amigo apenas '' ''

Emmanuel Muniko
fonte
5
Que valor sua resposta acrescenta sobre as outras respostas?
Hermann Döppes