Por que o C não é considerado uma linguagem 'orientada a objetos'?

91

Parece que o C tem seus próprios quase-objetos, como 'estruturas', que podem ser consideradas objetos (no modo de alto nível que normalmente pensamos).

E também, os arquivos C em si são basicamente "módulos" separados, certo? Então, os módulos também não são como 'objetos'? Estou confuso sobre o porquê C, que parece tão semelhante ao C ++, é considerado um baixo nível "processual" linguagem onde como C + + é de alto nível "orientada a objeto"

* edit: (esclarecimento) por que e onde, a linha é desenhada, para o que um 'objeto' é, e não é?

    
por Dark Templar 10.10.2011 / 22:44
fonte

12 respostas

101

It seems that C has its own quasi-objects such as 'structs' that can be considered as objects

Vamos juntos você e eu ler a página da Wikipedia sobre programação orientada a objetos e verificar os recursos de C Estruturas em estilo que correspondem ao que é tradicionalmente considerado como estilo orientado a objetos:

(OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions

As estruturas do C consistem em campos e métodos juntamente com suas interações ? Não.

Programming techniques may include features such as data abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance.

As estruturas do C fazem alguma dessas coisas de "primeira classe"? Não. A linguagem funciona contra você a cada passo do caminho.

the object-oriented approach encourages the programmer to place data where it is not directly accessible by the rest of the program

As estruturas C fazem isso? Não.

An object-oriented program will usually contain different types of objects, each type corresponding to a particular kind of complex data to be managed or perhaps to a real-world object or concept

As estruturas C fazem isso? Sim.

Objects can be thought of as wrapping their data within a set of functions designed to ensure that the data are used appropriately

Não.

each object is capable of receiving messages, processing data, and sending messages to other objects

Uma estrutura pode enviar e receber mensagens? Não. Pode processar dados? Não.

OOP data structures tend to "carry their own operators around with them"

Isso acontece em C? Não.

Dynamic dispatch ... Encapsulation ... Subtype polymorphism ... Object inheritance ... Open recursion ... Classes of objects ... Instances of classes ... Methods which act on the attached objects ... Message passing ... Abstraction

Algum desses recursos de estruturas C? Não.

Precisamente quais características de estruturas você acha que são "orientadas a objetos"? Porque não consigo encontrar nenhuma além do fato de que as estruturas definem tipos .

Agora, é claro, você pode criar estruturas com campos que sejam ponteiros para funções. Você pode fazer structs ter campos que são ponteiros para matrizes de ponteiros de função, correspondendo a tabelas de métodos virtuais. E assim por diante. Você pode, é claro, emular o C ++ em C. Mas essa é uma maneira não-idiomática de programar em C; você estaria melhor apenas usando C ++.

And also, C files themselves are basically separate "modules", right? Then aren't modules kind of like 'objects' too?

Mais uma vez, que características dos módulos você está pensando que os fazem agir como objetos? Os módulos suportam abstração, encapsulamento, mensagens, modularidade, polimorfismo e herança?

A abstração e o encapsulamento são muito fracos. Obviamente, os módulos são modulares; é por isso que eles são chamados de módulos. Mensagens? Apenas no sentido de que uma chamada de método é uma mensagem e módulos podem conter métodos. Polimorfismo? Não. Herança? Não. Os módulos são candidatos bastante fracos para "objetos".

    
por 10.10.2011 / 23:23
fonte
46

A palavra chave é "orientada", não "objeto". Mesmo o código C ++ que usa objetos, mas os usa como structs, não é objeto orientado .

C e C ++ podem fazer OOP (sem controle de acesso em C), mas a sintaxe para fazê-lo em C é inconveniente (para dizer o mínimo), enquanto a sintaxe em C ++ a torna muito convidativa. C é orientado para procedimentos, enquanto C ++ é orientado para objetos, apesar de capacidades centrais quase idênticas nesse sentido.

O código que usa objetos para implementar projetos que só podem ser feitos com objetos (geralmente significando vantagem de polimorfismo) é um código orientado a objetos. Código que usa objetos como pouco mais que malas de dados, mesmo usando herança em uma linguagem orientada a objetos, é na verdade apenas um código processual que é mais complicado do que precisa ser. O código em C, que usa ponteiros de função que são alterados em tempo de execução com structs cheios de dados, está meio que fazendo polimorfismo e pode ser considerado "orientado a objeto", mesmo em uma linguagem orientada para procedimentos.

    
por 10.10.2011 / 23:19
fonte
19

Com base nos principais de nível mais alto:

Um objeto é um encapsulamento de dados e comportamento de uma maneira interligada, de modo que eles operem como um todo, que pode ser instanciado várias vezes e trabalhado como uma caixa preta, se você conhecer a interface externa.

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 na herança e no polimorfismo ...

    
por 10.10.2011 / 22:58
fonte
6

"structs" são apenas dados. O teste rápido e sujo de "orientação a objetos" é: "Existe uma estrutura que permite encapsular código e dados como uma única unidade?". C falha e é, portanto, processual. C ++ passa esse teste.

    
por 10.10.2011 / 22:47
fonte
5

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.

  • Estruturas C podem ter dados (e esse é o objetivo principal deles)
  • As estruturas
  • C também podem definir ponteiros de função como dados
  • Estruturas C podem e geralmente têm um conjunto de funções associadas a elas, assim como métodos, apenas o ponteiro this não é passado implicitamente, mas você deve especificá-lo explicitamente como primeiro argumento para cada método projetado para lidar com a estrutura especificada. C ++ faz isso automaticamente para você, tanto quando você define e chama métodos class / struct.

OOP em C ++ estende os meios para abstrair dados. Alguns dizem que é prejudicial , enquanto outros consideram uma boa ferramenta quando usada corretamente.

  • O C ++ torna o ponteiro this implícito, não exigindo que o usuário o transmita para "métodos da classe / struct", desde que o tipo possa ser (pelo menos parcialmente) identificado.
  • O C ++ permite restringir o acesso a determinados métodos (funções de classe) e, portanto, permite mais "programação defensiva" ou "prova idiota".
  • O C ++ incentiva abstrações ao fornecer uma segurança mais strong ao introduzir
    1. O operador novo em vez de malloc + cast
    2. Modelos em vez de preencher os ponteiros
    3. Funções Inline recebendo valores digitados em vez de macros
    4. Construído em Polimorfismo que você não precisa implementar sozinho, que permite criar hierarquias de abstração , contratos e especializações .

No entanto, você encontrará muitos C "hackers" pregando como 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.

Inefficient abstracted programming models where two years down the road you notice that some abstraction wasn't very efficient, but now all your code depends on all the nice object models around it, and you cannot fix it without rewriting your app. -- Linus Torvalds

Outros tendem a vê-lo de maneira mais equilibrada, aceitando as vantagens e desvantagens.

C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off. -- Bjarne Stroustrup

    
por 11.10.2011 / 01:51
fonte
2

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 esconder os membros, por exemplo, ou podemos também ter herança com um relacionamento real "é um" e muito mais.

DEPOIS DE LER OS COMENTÁRIOS ABAIXO: Bem, é certo que (quase) tudo pode ser feito com C (isso é sempre verdade), mas à primeira vista eu pensei que o que separa c de c ++ é o como 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 esta resposta só se relacionará com problemas técnicos, mas acho que a principal diferença (como mencionado) é a maneira original que você pensa enquanto codifica, já que o C ++ oferece uma sintaxe construída melhor para fazer essas coisas, em vez de fazer OOP um jeito meio desajeitado em C.

    
por 10.10.2011 / 22:52
fonte
1

Você meio que disse isso sozinho. Enquanto C tem coisas que são como objetos, elas ainda não são objetos, e é por isso que C não é considerado uma linguagem OOP.

    
por 10.10.2011 / 22:49
fonte
1

Orientado a Objetos refere-se a um padrão de arquitetura (ou mesmo a um meta-padrão) e às linguagens que possuem recursos para ajudar a implementar ou impor o uso desse padrão.

Você pode implementar um design "OO" (o desktop Gnome é talvez o melhor exemplo de OO feito em C puro), eu já vi isso feito com COBOL!

No entanto, ser capaz de implementar uma dose de design OO não torna a linguagem OO. Os puristas argumentariam que Java e C ++ não são verdadeiramente OO, já que você não pode substituir ou herdar os "tipos" básicos, como "int" e "char", e Java não suporta múltiplas heranças. Mas como são as linguagens OO mais utilizadas e suportam a maior parte do paradigma dos programadores mais "reais" que são pagos para produzir códigos de trabalho, considerem-nas como as linguagens OO.

Por outro lado, o C suporta apenas estruturas (como o COBOL, Pascal e dezenas de outras linguagens procedurais), você poderia argumentar que suporta herança múltipla em que você pode usar qualquer função em qualquer parte de dados, mas a maioria considera isso como um bug em vez de um recurso.

    
por 11.10.2011 / 03:56
fonte
0

Vamos apenas olhar para a definição de OO:

  • Mensagens
  • Encapsulamento
  • Ligação tardia

C não fornece nenhum desses três. Em particular, não fornece Mensagens , que é o mais importante.

    
por 11.10.2011 / 04:00
fonte
0

Existem vários ingredientes chave para OO, mas os grandes são que a maioria do código não sabe o que está dentro de um objeto (eles vêem a interface de superfície, não a implementação), que o estado de um objeto é uma unidade gerenciada (ou seja, quando o objeto deixa de existir, assim como seu estado), e quando algum código invoca uma operação em um objeto, ele faz isso sem saber exatamente o que essa operação é ou envolve (tudo o que eles fazem é seguir um padrão para jogar uma "mensagem" sobre a parede).

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:

struct FooImpl;
typedef struct FooImpl *Foo;

Naturalmente, haverá a necessidade de uma função que construa Foo s (ou seja, uma fábrica) e que delegue parte do trabalho ao próprio objeto alocado (por exemplo, através de um método de "construtor"), e também ter uma maneira de descartar o objeto novamente (enquanto o deixa limpar através do método "destrutor"), mas isso é detalhes.

O envio de métodos (ou seja, mensagens) também pode ser feito por meio da convenção de que o primeiro elemento da estrutura é realmente um ponteiro para uma estrutura completa de ponteiros de função e que cada um desses ponteiros deve receber Foo seu primeiro argumento. Despacho, em seguida, torna-se uma questão de olhar para a função e chamá-lo com o direito de reescrever o argumento, o que não é tão difícil de fazer com um macro e um pouco astuto. (Essa tabela de funções é o núcleo do que uma classe realmente é em uma linguagem como C ++.)

Além disso, isso também lhe dá ligação tardia: todo o código de expedição 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 ir com 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 é uma linguagem OO. A chave é que C deixa você fazer todo o trabalho complicado de escrever as convenções e despachar mecanismo (ou usar uma biblioteca de terceiros). Isso é muito trabalho. Ele também não fornece suporte sintático ou semântico, portanto implementar um sistema de classes completo (com coisas como herança) seria desnecessariamente doloroso; Se você está 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.

    
por 11.10.2011 / 10:27
fonte
0

Eu acho que C é perfeitamente bom e decente para implementar conceitos orientados a objetos, shrug . A maioria das diferenças que eu vejo entre o subconjunto de denominador comum de linguagens consideradas orientadas a objetos são de natureza menor e sintática do meu ponto de vista pragmático.

Vamos começar com, digamos, ocultar 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 modela de forma eficaz a distinção public vs. private dos campos de dados à medida que obtemos as classes. E é bastante fácil de fazer e dificilmente anti-idiomático, como a biblioteca C padrão depende muito disso para conseguir esconder informações.

É claro que você perde a capacidade de controlar facilmente exatamente onde a estrutura é alocada na memória usando tipos opacos, mas isso é apenas uma diferença notável entre, digamos, C e C ++. C ++ é definitivamente uma ferramenta superior quando se compara sua capacidade de programar conceitos orientados a objetos sobre C enquanto ainda mantém controle sobre layouts de memória, mas isso não significa necessariamente que Java ou C # seja superior a C nesse sentido, já que esses dois fazem você perder completamente a capacidade de controlar onde os objetos são alocados na memória.

E precisamos usar uma sintaxe como fopen(file, ...); fclose(file); em vez de file.open(...); file.close(); mas grande whoop. Quem realmente se importa? Talvez apenas alguém que se apóia strongmente no preenchimento automático em seu IDE. Admito que pode ser um recurso muito útil do ponto de vista prático, mas talvez não seja uma questão que exija uma discussão sobre se uma linguagem é adequada para OOP.

Não temos a capacidade de implementar efetivamente os campos protected . 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 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 de membros protegidos que não sejam, pelo menos, um pouco suspeitos de se tornar um obstáculo de manutenção.

E é claro que temos que "emular" o polimorfismo OO com tabelas de ponteiros de função e apontadores para o despacho dinâmico com um pouco mais de clichê para inicializar os analógicos vtables e vptrs , mas um pouco de boilerplate nunca me causou muita dor.

A herança é da mesma maneira. Podemos facilmente modelar isso através da composição e, no funcionamento interno dos compiladores, resume-se à mesma coisa. É claro que perdemos a segurança do tipo se quisermos downcast , e lá eu diria que se você quiser fazer downcast , por favor não use C para ele porque o coisas que as pessoas fazem em C para emular downcasting podem ser horríveis do ponto de vista de segurança de tipos, mas eu prefiro que as pessoas não façam downcast . Tipo de segurança é algo que você pode facilmente começar a perder em C como o compilador oferece tanta margem de manobra para interpretar as coisas como apenas bits e bytes, sacrificando a capacidade de capturar erros em tempo de compilação, mas algumas linguagens consideradas orientadas a objetos nem mesmo estaticamente digitado.

Então, não sei, estou bem. É claro que eu não usaria o C para tentar criar uma base de código em grande escala que estivesse de acordo com os princípios do SOLID, mas não necessariamente devido a suas deficiências na frente orientada a objetos. Muitos dos recursos que eu perderia se tentasse usar o C para tal propósito estariam relacionados a recursos de linguagem não considerados diretamente como um pré-requisito para OOP, como segurança de tipo strong, destruidores que são automaticamente invocados quando objetos saem do escopo, operador sobrecarga, modelos / genéricos e tratamento de exceções. É quando estou perdendo esses recursos auxiliares que eu alcanço para C ++.

    
por 19.12.2017 / 01:33
fonte
-1

Não é uma má pergunta.

Se você vai chamar c uma linguagem OO, você precisará chamar quase todas as linguagens procedurais OO também. Por isso, tornaria o termo sem sentido. c não tem suporte de idioma para OO. Se tiver estruturas, mas as estruturas forem types sem classes.

Na verdade, c não tem muitos recursos em comparação com a maioria dos idiomas. É principalmente usado por sua velocidade, simplicidade, popularidade e suporte, incluindo toneladas de bibliotecas.

    
por 11.10.2011 / 10:06
fonte