Quando uma estrutura de dados (por exemplo, uma fila) é implementada usando uma linguagem OOP, alguns membros da estrutura de dados precisam ser privados (por exemplo, o número de itens na fila).
Uma fila também pode ser implementada em uma linguagem processual usando um struct
e um conjunto de funções que operam no struct
. No entanto, em uma linguagem processual, você não pode tornar os membros de um struct
particular. Os membros de uma estrutura de dados implementados em uma linguagem processual foram deixados em público ou houve algum truque para torná-los privados?
object-oriented
data-structures
history
Christopher
fonte
fonte
Respostas:
OOP não inventou o encapsulamento e não é sinônimo de encapsulamento. Muitas linguagens OOP não possuem modificadores de acesso no estilo C ++ / Java. Muitas linguagens não OOP têm várias técnicas disponíveis para oferecer encapsulamento.
Uma abordagem clássica para encapsulamento é o fechamento , conforme usado na programação funcional . Isso é significativamente mais antigo que o OOP, mas é de certa forma equivalente. Por exemplo, em JavaScript, podemos criar um objeto como este:
O
plus2
objeto acima não possui nenhum membro que permita acesso diretox
- é totalmente encapsulado. Oadd()
método é um fechamento sobre ax
variável.A linguagem C suporta alguns tipos de encapsulamento através de seu mecanismo de arquivo de cabeçalho , particularmente a técnica de ponteiro opaco . Em C, é possível declarar um nome de estrutura sem definir seus membros. Nesse ponto, nenhuma variável do tipo dessa estrutura pode ser usada, mas podemos usar ponteiros para essa estrutura livremente (porque o tamanho de um ponteiro de estrutura é conhecido em tempo de compilação). Por exemplo, considere este arquivo de cabeçalho:
Agora podemos escrever código que usa essa interface do Adder, sem ter acesso aos seus campos, por exemplo:
E aqui estariam os detalhes de implementação totalmente encapsulados:
Há também a classe de linguagens de programação modulares , que se concentra nas interfaces no nível do módulo. A família de idiomas ML incl. OCaml inclui uma abordagem interessante para módulos chamados functors . OOP ofuscou e modificou amplamente a programação modular, mas muitas vantagens pretendidas do OOP têm mais a ver com modularidade do que com orientação a objetos.
Há também a observação de que classes em linguagens OOP como C ++ ou Java geralmente não são usadas para objetos (no sentido de entidades que resolvem operações através de ligação tardia / envio dinâmico), mas apenas para tipos de dados abstratos (onde definimos uma interface pública que oculta detalhes de implementação interna). O artigo Sobre a compreensão da abstração de dados, revisitado (Cook, 2009) discute essa diferença com mais detalhes.
Mas sim, muitos idiomas não possuem mecanismo de encapsulamento. Nesses idiomas, os membros da estrutura são deixados públicos. No máximo, haveria uma convenção de nomenclatura que desencorajaria o uso. Por exemplo, acho que Pascal não tinha um mecanismo de encapsulamento útil.
fonte
Adder self = malloc(sizeof(Adder));
? Há uma razão para escrever indicadores esizeof(TYPE)
geralmente é desaprovada.sizeof(*Adder)
, porque*Adder
não é um tipo, assim como*int *
não é um tipo. A expressãoT t = malloc(sizeof *t)
é idiomática e correta. Veja minha edição.private static
variáveis em Java. Da mesma forma que C, você poderia usar ponteiros opacos para passar dados no Pascal sem declarar o que era. O MacOS clássico usou muitos ponteiros opacos, pois partes públicas e privadas de um registro (estrutura de dados) podem ser transmitidas juntas. Lembro-me de que o Gerenciador de Janelas fez muito disso, pois partes do Registro de Janelas eram públicas, mas algumas informações internas também foram incluídas._private_member
eoutput_property_
, ou técnicas mais avançadas para criar objetos imutáveis.Primeiro, ser processual versus orientado a objetos não tem nada a ver com público versus privado. Muitas linguagens orientadas a objetos não têm noção de controle de acesso.
Em segundo lugar, em "C" - que a maioria das pessoas chamaria de processual, e não orientado a objetos, existem muitos truques que você pode usar para tornar efetivamente as coisas privadas. Muito comum é usar ponteiros opacos (por exemplo, void *). Ou - você pode encaminhar declarar um objeto e simplesmente não defini-lo em um arquivo de cabeçalho.
foo.h:
foo.c:
Olhe para o SDK do Windows! Ele usa HANDLE e UINT_PTR, e coisas assim são identificadores genéricos para a memória usada nas APIs - efetivamente tornando as implementações privadas.
fonte
"Tipos de dados opacos" era um conceito bem conhecido quando me formei em ciência da computação há 30 anos. Não abordamos o POO, pois não era de uso comum na época e a "programação funcional" era considerada mais correta.
O Modula-2 tinha suporte direto para eles, consulte https://www.modula2.org/reference/modules.php .
Já foi explicado por Lewis Pringle como a declaração avançada de uma estrutura pode ser usada em C. Ao contrário do Módulo-2, uma função de fábrica precisava ser fornecida para criar o objeto. ( Os métodos virtuais também eram fáceis de implementar em C , pois o primeiro membro de uma estrutura era um ponteiro para outra estrutura que continha ponteiros de função para os métodos.)
Muitas vezes, a convenção também era usada. Por exemplo, qualquer campo começando com "_" não deve ser acessado fora do arquivo que possuía os dados. Isso foi facilmente aplicado pela criação de ferramentas de verificação personalizadas.
Todos os projetos de grande escala em que trabalhei (antes de migrar para C ++ e C #) tinham um sistema instalado para impedir que dados "particulares" fossem acessados pelo código errado. Foi apenas um pouco menos padronizado do que é agora.
fonte
Observe que existem muitos idiomas OO sem a capacidade interna de marcar membros como privados. Isso pode ser feito por convenção, sem a necessidade de o compilador impor a privacidade. Por exemplo, as pessoas costumam prefixar variáveis privadas com um sublinhado.
Existem técnicas para dificultar o acesso a variáveis "privadas", sendo a mais comum a linguagem PIMPL . Isso coloca suas variáveis privadas em uma estrutura separada, com apenas um ponteiro alocado nos seus arquivos de cabeçalho público. Isso significa uma desreferência extra e uma conversão para obter quaisquer variáveis privadas, algo como
((private_impl)(obj->private))->actual_value
, o que é irritante, portanto, na prática, raramente é usado.fonte
As estruturas de dados não tinham "membros", apenas campos de dados (supondo que fosse um tipo de registro). A visibilidade normalmente era definida para todo o tipo. No entanto, isso pode não ser tão limitador quanto você pensa, porque as funções não faziam parte do registro.
Vamos voltar e ter um pouco de história aqui ...
O paradigma de programação dominante antes da OOP foi chamado de programação estruturada . O principal objetivo inicial disso era evitar o uso de instruções de salto não estruturadas ("goto"). Esse é um paradigma orientado ao fluxo de controle (enquanto o OOP é mais orientado a dados), mas ainda era uma extensão natural dele tentar manter os dados logicamente estruturados exatamente como o código.
Outra superação da programação estruturada foi a ocultação de informações , a idéia de que as implementações da estrutura do código (que provavelmente mudam com bastante frequência) devem ser mantidas separadas da interface (que, idealmente, não mudará tanto). Agora é dogma, mas antigamente, muitas pessoas consideravam melhor para todo desenvolvedor conhecer os detalhes de todo o sistema, então essa foi uma vez uma ideia controversa. A edição original de The Mythical Man Month de Brook, na verdade, argumentou contra a ocultação de informações.
As linguagens de programação posteriores projetadas explicitamente para serem boas linguagens de programação estruturada (por exemplo, Modula-2 e Ada) geralmente incluíam informações ocultas como um conceito fundamental, construídas em torno de algum tipo de conceito de uma facilidade coesa de funções (e quaisquer tipos, constantes e objetos que possam ser necessários). No Modula-2, estes foram chamados "Módulos", no Ada "Pacotes". Muitas linguagens modernas de POO chamam o mesmo conceito de "namespaces". Esses namespaces eram a base organizacional do desenvolvimento nessas linguagens e, para a maioria dos propósitos, podiam ser usados de maneira semelhante às classes OOP (sem suporte real à herança, é claro).
Portanto, no Modula-2 e no Ada (83), você pode declarar qualquer rotina, tipo, constante ou objeto em um espaço para nome como privado ou público, mas se você tiver um tipo de registro, não haverá uma maneira (fácil) de declarar público alguns campos de registro e outros particulares. Todo o seu registro é público ou não.
fonte
object.method()
invocação é apenas açúcar sintático. IMHO importante - consulte o Princípio de acesso / referência uniforme de Meyer - mas ainda assim apenas açúcar sintático.object.method()
como uma forma alternativamethod(object, ...)
para pessoas que simplesmente não podiam dar o salto conceitual.Em C, você já pode passar ponteiros para tipos declarados, mas não definidos, como outros já disseram, restringindo o acesso a todos os campos.
Você também pode ter funções públicas e privadas, módulo a módulo. As funções declaradas estáticas no arquivo de origem não são visíveis para o exterior, mesmo se você tentar adivinhar o nome delas. Da mesma forma, você pode ter variáveis globais estáticas no nível do arquivo, o que geralmente é uma prática ruim, mas permite o isolamento em módulos.
Provavelmente é importante enfatizar que a restrição de acesso como uma convenção bem padronizada, em vez de uma construção imposta pela linguagem, funciona muito bem (consulte Python). Além disso, restringir o acesso aos campos de objetos apenas protegerá o programador quando houver necessidade de alterar o valor dos dados dentro de um objeto após a criação. O que já é um cheiro de código. Indiscutivelmente, C e, em particular, a
const
palavra-chave do C ++ para métodos e argumentos de função são uma ajuda muito maior para o programador do que o bastante pobre do Javafinal
.fonte
static
dados e operações globais (o que significava que não foram apresentados ao vinculador para uso em outras compilações). Você pode argumentar plausivelmente qualquer apoio C teve para boas práticas de design de software, além de que era praticamente um truque, e não parte do projeto original da parte traseira idioma em 1972.Se sua definição de Público for a capacidade de acessar a implementação e dados / propriedades por meio de seu próprio código a qualquer momento, a resposta é simplesmente: Sim . No entanto, foi abstraído por diversos meios - dependendo do idioma.
Espero que isso tenha respondido sucintamente à sua pergunta.
fonte
Aqui está um contra-exemplo muito simples: em Java,
interface
s definem objetos, masclass
es não. Aclass
define um tipo de dados abstrato, não um objeto.Portanto, sempre que você usa
private
umclass
em Java, você tem um exemplo de uma estrutura de dados com membros privados que não são orientados a objetos.fonte