Pergunta

Você deveria usar variáveis ​​de membro protegidas?Quais são as vantagens e quais problemas isso pode causar?

Foi útil?

Solução

Você deveria usar variáveis ​​de membro protegidas?

Depende de quão exigente você é quanto ao estado de ocultação.

  • Se você não deseja nenhum vazamento de estado interno, declarar todas as suas variáveis ​​de membro como privadas é o caminho a seguir.
  • Se você realmente não se importa que as subclasses possam acessar o estado interno, então protegido é bom o suficiente.

Se um desenvolvedor aparecer e subclassificar sua classe, ele poderá bagunçar tudo porque não a entenderá completamente.Com membros privados, além da interface pública, eles não podem ver os detalhes específicos da implementação de como as coisas estão sendo feitas, o que lhe dá a flexibilidade de alterá-las posteriormente.

Outras dicas

O sentimento geral hoje em dia é que causam acoplamento indevido entre classes derivadas e suas bases.

Eles não têm nenhuma vantagem específica sobre métodos/propriedades protegidos (era uma vez eles poderiam ter uma ligeira vantagem de desempenho) e também eram mais usados ​​em uma época em que a herança muito profunda estava na moda, o que não é no momento.

Geralmente, se algo não é deliberadamente concebido como público, eu o torno privado.

Se surgir uma situação em que eu precise acessar essa variável ou método privado de uma classe derivada, eu mudo de privado para protegido.

Isso quase nunca acontece - eu realmente não sou fã de herança, pois não é uma maneira particularmente boa de modelar a maioria das situações.De qualquer forma, continue, não se preocupe.

Eu diria que isso é bom (e provavelmente a melhor maneira de fazer isso) para a maioria dos desenvolvedores.

O simples fato da questão é, se algum outro desenvolvedor aparecer um ano depois e decidir que precisa de acesso à sua variável de membro privada, ele simplesmente editará o código, mudará para protegido e continuará com seus negócios.

As únicas exceções reais a isso são se você estiver enviando DLLs binárias em formato de caixa preta para terceiros.Isso consiste basicamente na Microsoft, nos fornecedores de 'Custom DataGrid Control' e talvez em alguns outros aplicativos grandes que vêm com bibliotecas de extensibilidade.A menos que você esteja nessa categoria, não vale a pena gastar tempo/esforço se preocupando com esse tipo de coisa.

Em geral, eu manteria suas variáveis ​​de membro protegidas nos raros casos em que você também tem controle total sobre o código que as utiliza.Se você estiver criando uma API pública, eu diria nunca.Abaixo, nos referiremos à variável membro como uma “propriedade” do objeto.

Aqui está o que sua superclasse não pode faça depois de tornar uma variável de membro protegida em vez de privada com acessadores:

  1. crie preguiçosamente um valor dinamicamente quando a propriedade estiver sendo lida.Se você adicionar um método getter protegido, poderá criar o valor preguiçosamente e passá-lo de volta.

  2. saber quando a propriedade foi modificada ou excluída.Isso pode introduzir bugs quando a superclasse faz suposições sobre o estado daquela variável.Criar um método setter protegido para a variável mantém esse controle.

  3. Defina um ponto de interrupção ou adicione saída de depuração quando a variável for lida ou gravada.

  4. Renomeie essa variável de membro sem pesquisar todo o código que possa utilizá-la.

Em geral, acho que seria raro recomendar a criação de uma variável de membro protegida.É melhor gastar alguns minutos expondo a propriedade por meio de getters/setters do que horas depois rastreando um bug em algum outro código que modificou a variável protegida.Não apenas isso, mas você está protegido contra a adição de funcionalidades futuras (como carregamento lento) sem quebrar o código dependente.É mais difícil fazer isso mais tarde do que agora.

No nível de design, pode ser apropriado usar uma propriedade protegida, mas para implementação não vejo vantagem em mapear isso para uma variável de membro protegida em vez de métodos acessadores/mutadores.

Variáveis-membro protegidas têm desvantagens significativas porque permitem efetivamente o acesso do código do cliente (a subclasse) ao estado interno da classe base.Isso evita que a classe base mantenha efetivamente seus invariantes.

Pela mesma razão, variáveis-membro protegidas também tornam a escrita de código multithread seguro significativamente mais difícil, a menos que seja garantido constante ou confinado a um único thread.

Os métodos de acesso/mutador oferecem consideravelmente mais estabilidade de API e flexibilidade de implementação sob manutenção.

Além disso, se você é um purista OO, os objetos colaboram/comunicam enviando mensagens, não lendo/definindo estado.

Em troca, oferecem muito poucas vantagens.Eu não os removeria necessariamente do código de outra pessoa, mas eu mesmo não os uso.

A questão principal para mim é que, depois de tornar uma variável protegida, você não poderá permitir que nenhum método da sua classe seja confiar depende de seu valor estar dentro de um intervalo, porque uma subclasse sempre pode colocá-lo fora do intervalo.

Por exemplo, se eu tiver uma classe que define a largura e a altura de um objeto renderizável e tornar essas variáveis ​​protegidas, não poderei fazer suposições sobre (por exemplo) a proporção da imagem.

Criticamente, posso nunca faça essas suposições a qualquer momento a partir do momento em que o código for lançado como uma biblioteca, pois mesmo que eu atualize meus setters para manter a proporção, não tenho garantia de que as variáveis ​​​​estão sendo definidas por meio dos setters ou acessadas por meio dos getters no código existente.

Nem qualquer subclasse da minha classe pode optar por fazer essa garantia, pois também não pode impor os valores das variáveis, mesmo que esse seja o objetivo de sua subclasse.

Como um exemplo:

  • Eu tenho uma classe retângulo com largura e altura armazenadas como variáveis ​​protegidas.
  • Uma subclasse óbvia (dentro do meu contexto) é uma classe "DisplayedRectangle", onde a única diferença é que eu restrinjo as larguras e alturas a valores válidos para uma exibição gráfica.
  • Mas isso é impossível agora, já que minha classe DisplayedRectangle não pode realmente restringir esses valores, já que qualquer subclasse dela poderia substituir os valores diretamente, embora ainda fosse tratada como um DisplayedRectangle.

Ao restringir as variáveis ​​a serem privadas, posso então impor o comportamento desejado por meio de setters ou getters.

Na maioria das vezes, é perigoso usar protected porque você quebra um pouco o encapsulamento da sua classe, que poderia muito bem ser quebrado por uma classe derivada mal projetada.

Mas tenho um bom exemplo:Digamos que você possa algum tipo de contêiner genérico.Possui uma implementação interna e acessadores internos.Mas você precisa oferecer pelo menos 3 acessos públicos aos seus dados:mapa, hash_map, semelhante a um vetor.Então você tem algo como:

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

Usei esse tipo de código há menos de um mês (então o código está na memória).Depois de pensar um pouco, acredito que, embora o contêiner Base genérico deva ser uma classe abstrata, mesmo que possa funcionar muito bem, porque usar Base diretamente seria tão chato que deveria ser proibido.

Resumo Assim, você protegeu os dados usados ​​pela classe derivada.Ainda assim, devemos levar em conta o fato de que a classe Base deve ser abstrata.

Resumindo, sim.

Variáveis ​​de membro protegidas permitem acesso à variável de qualquer subclasse, bem como de qualquer classe no mesmo pacote.Isso pode ser muito útil, especialmente para dados somente leitura.No entanto, não acredito que eles sejam necessários, porque qualquer uso de uma variável de membro protegida pode ser replicado usando uma variável de membro privada e alguns getters e setters.

Apenas para o registro, sob o item 24 de "C ++ excepcional", em uma das notas de rodapé, Sutter diz "Você nunca escreveria uma classe que possui uma variável de membro público ou protegido.certo?(Independentemente do mau exemplo dado por algumas bibliotecas.)"

Para informações detalhadas sobre modificadores de acesso .Net vá aqui

Não há vantagens ou desvantagens reais nas variáveis-membro protegidas; é uma questão do que você precisa em sua situação específica.Em geral, é uma prática aceita declarar variáveis-membro como privadas e permitir acesso externo por meio de propriedades.Além disso, algumas ferramentas (por ex.alguns mapeadores O/R) esperam que os dados do objeto sejam representados por propriedades e não reconhecem variáveis ​​de membro públicas ou protegidas.Mas se você sabe que deseja que suas subclasses (e SOMENTE suas subclasses) acessem uma determinada variável, não há razão para não declará-la como protegida.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top