Parece que C tem seus próprios quase-objetos, como "estruturas" que podem ser considerados objetos (da maneira de alto nível que normalmente pensamos).
E também, os arquivos C são basicamente "módulos" separados, certo? Então os módulos também não são como 'objetos'? Estou confuso sobre o motivo pelo qual C, que parece tão semelhante ao C ++, é considerado uma linguagem "procedural" de baixo nível, onde C ++ é um "orientado a objetos" de alto nível.
* edit: (esclarecimento) por que e onde, a linha é desenhada, pois o que é um 'objeto' e não é?
object-oriented
procedural
Templário Sombrio
fonte
fonte
Respostas:
Vamos juntos, você e eu, ler a página da Wikipedia sobre programação orientada a objetos e verificar os recursos das estruturas no estilo C que correspondem ao que é tradicionalmente considerado estilo orientado a objetos:
As estruturas C consistem em campos e métodos, juntamente com suas interações ? Não.
As estruturas C fazem alguma dessas coisas de maneira "de primeira classe"? Não. A linguagem funciona contra você a cada passo do caminho.
As estruturas C fazem isso? Não.
As estruturas C fazem isso? Sim.
Não.
Uma estrutura pode enviar e receber mensagens? Não. Ele pode processar dados? Não.
Isso acontece em C? Não.
Há algum desses recursos das estruturas C? Não.
Precisamente, quais características das estruturas você acha que são "orientadas a objetos"? Porque eu não posso encontrar qualquer que não seja o fato de que estruturas definem tipos .
Agora, é claro que você pode criar estruturas que possuem campos que são indicadores de funções. Você pode fazer com que as estruturas tenham campos que são ponteiros para matrizes de ponteiros de função, correspondentes a tabelas de métodos virtuais. E assim por diante. É claro que você pode emular C ++ em C. Mas essa é uma maneira muito não-idiomática de programar em C; seria melhor você usar C ++.
Novamente, em quais características dos módulos você pensa que os fazem agir como objetos? Os módulos suportam abstração, encapsulamento, sistema de mensagens, modularidade, polimorfismo e herança?
Abstração e encapsulamento são bem fracos. Obviamente, os módulos são modulares; é por isso que eles são chamados de módulos. Mensagens? Somente no sentido de que uma chamada de método é uma mensagem e os módulos podem conter métodos. Polimorfismo? Não. Herança? Não. Módulos são candidatos bastante fracos para "objetos".
fonte
A palavra-chave é "orientada", não "objeto". Mesmo o código C ++ que usa objetos, mas os usa como estruturas, não é orientado a objetos .
C e C ++ podem fazer OOP (além de nenhum controle de acesso em C), mas a sintaxe para fazê-lo em C é inconveniente (para dizer o mínimo), enquanto a sintaxe em C ++ o torna muito convidativo. C é orientado a procedimentos, enquanto C ++ é orientado a objetos, apesar dos recursos principais quase idênticos a esse respeito.
O código que usa objetos para implementar projetos que só podem ser feitos com objetos (geralmente significa tirar vantagem do polimorfismo) é um código orientado a objetos. O código que usa objetos com pouco mais do que pacotes de dados, mesmo usando herança em uma linguagem orientada a objetos, é realmente apenas um código processual que é mais complicado do que precisa ser. Código em C que usa ponteiros de função que são alterados em tempo de execução com estruturas cheias de dados está meio que polimorfismo, e pode-se dizer que é "orientado a objetos", mesmo em uma linguagem orientada a procedimentos.
fonte
Com base nos principais de nível mais alto:
Um objeto é um encapsulamento de dados e comportamento de maneira interligada, de modo que eles operem como um todo, que podem ser instanciados várias vezes e trabalhados como uma caixa preta, se você conhece a interface externa.
As estruturas contêm dados, mas nenhum comportamento e, portanto, não podem ser considerados objetos.
Os módulos contêm comportamento e dados, mas não são encapsulados de forma que os dois estejam relacionados e certamente não podem ser instanciados várias vezes.
E isso é antes de você entrar em herança e polimorfismo ...
fonte
"structs" são apenas dados. O teste rápido e sujo usual de "orientação a objetos" é: "Existe uma estrutura que permite que códigos e dados sejam encapsulados como uma única unidade?". C falha nisso e, portanto, é processual. C ++ passa nesse teste.
fonte
this
ponteiro explícito , mas, nesse caso, os dados e os meios para processar os dados serão encapsulados dentro da estrutura.#include
de d para ele, e menos qualquer coisa removido por não ser condicionalmente incluído (#if
,#ifdef
e afins).C, assim como o C ++, tem a capacidade de fornecer Abstração de Dados , que é um idioma do paradigma de programação orientada a objetos que existia antes dele.
OOP em C ++ estende os meios para abstrair dados. Alguns dizem que é prejudicial , enquanto outros consideram uma boa ferramenta quando usada corretamente.
No entanto, você encontrará muitos "hackers" C pregando como o C é perfeitamente capaz da quantidade certa de abstração e como a sobrecarga criada pelo C ++ apenas os distrai da solução do problema real.
Outros tendem a vê-lo de uma maneira mais equilibrada, aceitando as vantagens e as desvantagens.
fonte
Você precisa olhar para o outro lado da moeda: C ++.
Em OOP, pensamos em um objeto abstrato (e projetamos o programa de acordo), por exemplo, um carro que pode parar, acelerar, virar à esquerda ou à direita, etc. Uma estrutura com um conjunto de funções simplesmente não se encaixa no conceito.
Com objetos "reais", precisamos ocultar os membros, por exemplo, ou também podemos ter herança com um relacionamento real "é um" e muito mais.
APÓS LER OS COMENTÁRIOS ABAIXO: Bem, é certo que (quase) tudo pode ser feito com C (isso sempre é verdade), mas, à primeira vista, pensei que o que separa c de c ++ é a maneira que você pensa ao criar um programa.
A única coisa que realmente faz a diferença é a imposição de políticas pelo compilador . ou seja, função virtual pura, e tal. mas essa resposta só se relaciona a problemas técnicos, mas acho que a principal diferença (como mencionada) é a maneira original como você pensa enquanto codifica, pois o C ++ oferece uma sintaxe melhor incorporada para fazer essas coisas, em vez de fazer OOP em uma maneira um pouco desajeitada em C.
fonte
Você meio que disse isso sozinho. Enquanto C tem coisas que são como objetos semelhantes, eles ainda não são objetos, e é por isso que C não é considerado uma linguagem OOP.
fonte
Orientado a objeto refere-se a um padrão arquitetural (ou mesmo a um meta-padrão) e às linguagens que possuem recursos para ajudar a implementar ou exigir o uso desse padrão.
Você pode implementar um design "OO" (a área de trabalho do Gnome é talvez o melhor exemplo de OO feito em C puro). Eu já vi isso com o COBOL!
No entanto, ser capaz de implementar uma dose de projeto OO não torna a linguagem OO. Os puristas argumentam que Java e C ++ não são verdadeiramente OO, pois você não pode substituir ou herdar os "tipos" básicos, como "int" e "char", e Java não suporta herança múltipla. Porém, como são as linguagens OO mais usadas e suportam a maioria dos paradigmas, os programadores "reais" que são pagos para produzir código de trabalho os consideram as linguagens OO.
C, por outro lado, suporta apenas estruturas (como COBOL, Pascal e dezenas de outras linguagens processuais), você poderia argumentar que suporta herança múltipla, pois você pode usar qualquer função em qualquer parte dos dados, mas a maioria consideraria isso um erro. do que um recurso.
fonte
Vamos apenas olhar para a definição de OO:
C não fornece nenhum desses três. Em particular, ele não fornece o Messaging , que é o mais importante.
fonte
static
funções internas ( ) e membros de dados.Existem vários ingredientes principais para o OO, mas os principais são que a maioria do código não sabe o que está dentro de um objeto (eles veem a interface da superfície, não a implementação), que o estado de um objeto é uma unidade gerenciada (ou seja, quando o objeto deixa de existir, o mesmo ocorre com o seu estado) e, quando algum código invoca uma operação em um objeto, eles o fazem sem saber exatamente o que essa operação é ou envolve (tudo o que fazem é seguir um padrão para lançar um “Mensagem” por cima do muro).
C encapsula muito bem; código que não vê a definição de uma estrutura não pode (legitimamente) espiar dentro dela. Tudo o que você precisa fazer é colocar uma definição como essa em um arquivo de cabeçalho:
Obviamente, haverá uma necessidade de uma função que construa
Foo
s (ou seja, uma fábrica) e que deva delegar parte do trabalho ao próprio objeto alocado (ou seja, através de um método "construtor"), e também de ter uma maneira de descartar o objeto novamente (ao mesmo tempo em que limpa através do método "destruidor"), mas isso é detalhes.O envio de métodos (isto é, mensagens) também pode ser feito através da convenção de que o primeiro elemento da estrutura é realmente um ponteiro para uma estrutura cheia de ponteiros de função e que cada um desses ponteiros de função deve ter
Foo
como primeiro argumento. A expedição passa a ser uma questão de procurar a função e chamá-la com o argumento correto reescrito, o que não é tão difícil de fazer com uma macro e um pouco de astúcia. (Essa tabela de funções é o núcleo do que realmente é uma classe em uma linguagem como C ++.)Além disso, isso também fornece uma ligação tardia: tudo o que o código de despacho sabe é que está invocando um deslocamento específico em uma tabela apontada pelo objeto. Isso só precisa ser definido durante a alocação e inicialização do objeto. É possível usar esquemas de despacho ainda mais complexos que compram mais dinamismo de tempo de execução (a um custo de velocidade), mas são cerejas no topo do mecanismo básico.
No entanto, isso não significa que C seja uma linguagem OO. A chave é que C deixa você fazer todo o trabalho complicado de escrever as convenções e o mecanismo de envio (ou usar uma biblioteca de terceiros). Isso dá muito trabalho. Também não fornece suporte sintático ou semântico, portanto, implementar um sistema de classe completo (com coisas como herança) seria desnecessariamente doloroso; se você estiver lidando com um problema complexo que é bem descrito por um modelo OO, uma linguagem OO será muito útil para escrever a solução. A complexidade extra pode ser justificada.
fonte
Eu acho que C é perfeitamente bom e decente para implementar conceitos orientados a objetos, encolher os ombros . A maioria das diferenças que eu vejo entre o subconjunto denominador comum de linguagens consideradas orientadas a objetos são de natureza menor e sintática do meu tipo de ponto de vista pragmático.
Vamos começar com, digamos, ocultação de informações. Em C, podemos conseguir isso simplesmente ocultando a definição de uma estrutura e trabalhando com ela através de ponteiros opacos. Isso efetivamente modela a distinção
public
vs.private
campos de dados à medida que obtemos as classes. E é fácil o suficiente e dificilmente anti-idiomático, pois a biblioteca C padrão depende muito disso para obter informações ocultas.É claro que você perde a capacidade de controlar facilmente exatamente onde a estrutura é alocada na memória usando tipos opacos, mas essa é apenas uma diferença notável entre, digamos, C e C ++. Definitivamente, o C ++ é uma ferramenta superior ao comparar sua capacidade de programar conceitos orientados a objetos sobre C, mantendo o controle sobre layouts de memória, mas isso não significa necessariamente que Java ou C # seja superior a C nesse sentido, pois esses dois fazem você perder completamente a capacidade de controlar onde os objetos estão alocados na memória.
E nós temos que usar uma sintaxe como
fopen(file, ...); fclose(file);
em oposição afile.open(...); file.close();
mas grande grito. Quem realmente se importa? Talvez apenas alguém que se apóia fortemente na conclusão automática em seu IDE. Admito que possa ser um recurso muito útil do ponto de vista prático, mas talvez não seja necessário um debate sobre se um idioma é adequado para o POO.Não temos a capacidade de implementar efetivamente os
protected
campos. Eu vou me submeter totalmente lá. Mas não acho que exista uma regra concreta que diga: " Todos os idiomas OO devem ter um recurso para permitir que as subclasses acessem membros de uma classe base que ainda não devem ser acessados por clientes normais ". Além disso, raramente vejo casos de uso para membros protegidos que não suspeitam de se tornar um obstáculo de manutenção.E é claro que precisamos "emular" o polimorfismo OO com tabelas de ponteiros de função e ponteiros para eles para envio dinâmico com um pouco mais de clichê para inicializar aqueles analógicos
vtables
evptrs
, mas um pouco de clichê nunca me causou muita dor.A herança é da mesma maneira. Podemos modelar isso facilmente através da composição e, no funcionamento interno dos compiladores, tudo se resume à mesma coisa. É claro que perdemos a segurança do tipo se queremos fazer downcast , e aí eu diria que se você quiser fazer downcast , não use C para isso, porque as coisas que as pessoas fazem em C para emular o downcast podem ser horríveis para um tipo ponto de vista da segurança, mas prefiro que as pessoas não fiquem abatidas . Segurança de tipo é algo que você pode facilmente perder em C, pois o compilador oferece muita margem de manobra para interpretar coisas como apenas bits e bytes, sacrificando a capacidade de detectar possíveis erros no tempo de compilação, mas algumas linguagens consideradas não orientadas a objetos mesmo digitado estaticamente.
Então não sei, acho que está bem. É claro que eu não usaria C para tentar criar uma base de código em larga escala que esteja em conformidade com os princípios do SOLID, mas isso não é necessariamente devido a suas falhas na frente orientada a objetos. Muitos dos recursos que eu perderia se tentasse usar C para esse objetivo estariam relacionados a recursos de linguagem não considerados diretamente um pré-requisito para OOP, como segurança de tipo forte, destruidores que são automaticamente invocados quando objetos ficam fora do escopo, operador sobrecarga, modelos / genéricos e tratamento de exceções. É quando sinto falta dos recursos auxiliares que alcanço em C ++.
fonte
foo_create
efoo_destroy
efoo_clone
, por exemplostruct Foo
nesse caso é garantir que seus membros de dados não possam ser acessados e mutados pelo mundo externo, que tipos opacos (declarados mas não definidos para o mundo externo) fornecem imediatamente. É sem dúvida uma forma mais forte de ocultar informações, a par com a de umpimpl
em C ++.Não é uma pergunta ruim.
Se você quiser chamar c de uma linguagem OO, também precisará chamar todas as linguagens procedurais de OO. Então isso tornaria o termo sem sentido. c não tem suporte a idiomas para OO. Se possui estruturas, mas estruturas
types
não são classes.Na verdade, c não possui muitos recursos em comparação com a maioria dos idiomas. É usado principalmente por sua velocidade, simplicidade, popularidade e suporte, incluindo toneladas de bibliotecas.
fonte