¿Por qué C no se considera un lenguaje 'orientado a objetos'?

91

Parece que C tiene sus propios cuasi objetos, como "estructuras", que pueden considerarse objetos (en la forma de alto nivel en que normalmente pensaríamos).

Y también, los archivos C son básicamente "módulos" separados, ¿verdad? Entonces, ¿no son los módulos algo así como 'objetos' también? Estoy confundido en cuanto a por qué C, que parece tan similar a C ++, se considera un lenguaje "de procedimiento" de bajo nivel en el que C ++ está "orientado a objetos" de alto nivel

* edit: (aclaración) ¿por qué y dónde, se dibuja la línea, para lo que es un 'objeto' y no lo es?

    
pregunta Dark Templar 10.10.2011 - 22:44

12 respuestas

101
  

Parece que C tiene sus propios cuasi objetos, como 'estructuras', que pueden considerarse como objetos

Juntos, usted y yo leemos la página de Wikipedia sobre programación orientada a objetos y comprobamos las características de C Estructuras de estilo que corresponden a lo que tradicionalmente se considera un estilo orientado a objetos:

  

(OOP) es un paradigma de programación que utiliza "objetos": estructuras de datos que consisten en campos y métodos de datos junto con sus interacciones

¿Las estructuras C constan de campos y métodos junto con sus interacciones ? No.

  

Las técnicas de programación pueden incluir características como la abstracción de datos, la encapsulación, la mensajería, la modularidad, el polimorfismo y la herencia.

¿Las estructuras de C hacen alguna de estas cosas de manera "primera clase"? No. El lenguaje funciona en tu contra en cada paso del camino.

  

el enfoque orientado a objetos alienta al programador a colocar los datos donde el resto del programa no los puede acceder directamente

¿Las estructuras de C hacen esto? No.

  

Un programa orientado a objetos generalmente contendrá diferentes tipos de objetos, cada tipo correspondiente a un tipo particular de datos complejos para ser administrados o tal vez a un objeto o concepto del mundo real

¿Las estructuras de C hacen esto? Sí.

  

se puede pensar que los objetos envuelven sus datos dentro de un conjunto de funciones diseñadas para garantizar que los datos se utilicen de forma adecuada

No.

  

cada objeto es capaz de recibir mensajes, procesar datos y enviar mensajes a otros objetos

¿Puede una estructura enviar y recibir mensajes? No. ¿Puede procesar datos? No.

  

Las estructuras de datos OOP tienden a "llevar a sus propios operadores con ellos"

¿Esto sucede en C? No.

  

Despacho dinámico ... Encapsulación ... Polimorfismo de subtipo ... Herencia de objetos ...   Abrir recursión ... Clases de objetos ... Instancias de clases ... Métodos que actúan sobre los objetos adjuntos ... Paso de mensajes ... Abstracción

¿Alguna de estas características de C structs? No.

¿Precisamente qué características de las estructuras crees que están "orientadas a objetos"? Porque no puedo encontrar ninguna aparte del hecho de que las estructuras definen tipos .

Ahora, por supuesto, puede hacer estructuras que tengan campos que sean punteros a funciones. Puede hacer que las estructuras tengan campos que sean punteros a matrices de punteros de función, correspondientes a tablas de métodos virtuales. Y así. Por supuesto, puede emular C ++ en C. Pero esa es una forma muy no idiomática de programar en C; estarías mejor usando C ++.

  

Y también, los archivos C son básicamente "módulos" separados, ¿verdad? Entonces, ¿no son los módulos algo así como 'objetos' también?

Una vez más, ¿qué características de los módulos estás pensando que los hacen actuar como objetos? ¿Los módulos son compatibles con la abstracción, la encapsulación, la mensajería, la modularidad, el polimorfismo y la herencia?

La abstracción y la encapsulación son bastante débiles. Obviamente los módulos son modulares; Por eso se llaman módulos. ¿Mensajería? Solo en el sentido de que una llamada a un método es un mensaje y los módulos pueden contener métodos. ¿Polimorfismo? No ¿Herencia? No Los módulos son candidatos bastante débiles para "objetos".

    
respondido por el Eric Lippert 10.10.2011 - 23:23
46

La palabra clave es "orientada", no "objeto". Incluso el código C ++ que usa objetos pero los usa como estructuras no está orientado a objetos .

C y C ++ pueden hacer OOP (además de no tener control de acceso en C), pero la sintaxis para hacerlo en C es inconveniente (por decir lo menos), mientras que la sintaxis en C ++ lo hace muy atractivo. C está orientado a procedimientos, mientras que C ++ está orientado a objetos, a pesar de las capacidades básicas casi idénticas en ese sentido.

El código que usa objetos para implementar diseños que solo pueden hacerse con objetos (lo que generalmente significa aprovechar el polimorfismo) es un código orientado a objetos. El código que utiliza objetos como poco más que bolsas de datos, incluso el uso de la herencia en un lenguaje orientado a objetos, es realmente un código de procedimiento que es más complicado de lo que debe ser. El código en C que usa punteros de función que se cambian en el tiempo de ejecución con estructuras llenas de datos está haciendo un poco de polimorfismo, y se puede decir que está "orientado a objetos", incluso en un lenguaje orientado a procedimientos.

    
respondido por el kylben 10.10.2011 - 23:19
19

Basado en los directores de más alto nivel:

Un objeto es una encapsulación de datos y comportamientos de manera interconectada, de manera que funcionan como un todo que se puede instanciar varias veces y trabajar como una caja negra si conoce la interfaz externa.

Las estructuras contienen datos pero no comportan y, por lo tanto, no pueden considerarse objetos.

Los módulos contienen tanto comportamiento como datos, pero no están encapsulados de tal manera que los dos estén relacionados y, por lo tanto, no puedan ser instanciados varias veces.

Y eso es antes de llegar a la herencia y el polimorfismo ...

    
respondido por el Jon Hopkins 10.10.2011 - 22:58
6

Las "estructuras" son solo datos. La prueba habitual rápida y sucia de "orientación a objetos" es: "¿Existe una estructura que permita que el código y los datos se encapsulen como una sola unidad?". C falla en eso, y por lo tanto es procesal. C ++ pasa esa prueba.

    
respondido por el Brian Knoblauch 10.10.2011 - 22:47
5

C, al igual que C ++, tiene la capacidad de proporcionar Data Abstraction , que es uno idioma del paradigma de programación orientada a objetos que existía antes de él.

  • Las estructuras C pueden tener datos (y ese es su propósito principal)
  • Las estructuras C también pueden definir punteros de función como datos
  • Las estructuras C pueden y, a menudo, tienen un conjunto de funciones asociadas a ellas, al igual que los métodos, solo el puntero este no se pasa implícitamente, pero debe especificarlo explícitamente como el primer argumento de cada método. Diseñado para manejar la estructura especificada. C ++ hace esto automáticamente por usted, tanto cuando define como llama los métodos de clase / estructura.

OOP en C ++ extiende los medios para resumir datos. Algunos dicen que es perjudicial , mientras que otros lo consideran una buena herramienta cuando se usa correctamente.

  • C ++ hace que el puntero este sea implícito al no requerir que el usuario lo pase a "métodos de la clase / estructura" siempre que el tipo pueda ser identificado (al menos en parte).
  • C ++ le permite restringir el acceso a ciertos métodos (funciones de clase) y, por lo tanto, permite más "programación defensiva" o "prueba de idiotas".
  • C ++ fomenta las abstracciones al proporcionar una mayor seguridad de tipos al introducir
    1. El operador nuevo en lugar de malloc + cast
    2. Plantillas en lugar de punteros nulos
    3. Funciones en línea que reciben valores escritos en lugar de macros
    4. Integrado en Polimorfismo que no tiene que implementar, lo que le permite crear jerarquías de abstracción , contratos y especializaciones .

Sin embargo, encontrará muchos "piratas informáticos" en C que predican cómo C es perfectamente capaz de la cantidad justa de abstracción y cómo la sobrecarga creada por C ++ solo los distrae de resolver el problema real.

  

Modelos de programación abstraídos ineficientes donde dos años más tarde      Notan que alguna abstracción no fue muy eficiente, pero ahora todo      su código depende de todos los simpáticos modelos de objetos que lo rodean, y usted      no puede arreglarlo sin volver a escribir su aplicación. - Linus Torvalds

Los demás tienden a verlo de una manera más equilibrada, aceptando tanto las ventajas como las desventajas.

  

C hace que sea más fácil dispararte en el pie; C ++ lo hace más difícil, pero cuando lo haces te arranca la pierna entera. - Bjarne Stroustrup

    
respondido por el Yam Marcovic 11.10.2011 - 01:51
2

Debes mirar al otro lado de la moneda: C ++.

En POO, pensamos en un objeto abstracto (y diseñamos el programa en consecuencia), por ejemplo, un automóvil que puede detenerse, acelerar, girar a la izquierda o a la derecha, etc. Una estructura con un conjunto de funciones simplemente no se ajusta al concepto .

Con los objetos "reales" necesitamos ocultar los miembros, por ejemplo, o también podemos tener herencia con una relación real "es una" y muchas más.

DESPUÉS DE LEER LOS COMENTARIOS A CONTINUACIÓN: Bueno, es correcto que (casi) todo se puede hacer con C (eso siempre es cierto), pero a primera vista pensé que lo que separa a c de c ++ es el Cómo piensas al diseñar un programa.

Lo único que realmente hace la diferencia es la imposición de políticas por parte del compilador . es decir, función virtual pura, y tal. pero esta respuesta solo se relacionará con problemas técnicos, pero creo que la diferencia principal (como se mencionó) es la forma original en que piensa mientras codifica, ya que C ++ le proporciona una sintaxis mejor incorporada para hacer tales cosas, en lugar de hacer OOP en una forma un tanto torpe en C.

    
respondido por el Guy L 10.10.2011 - 22:52
1

Tú mismo lo dijiste. Si bien C tiene cosas que son como objetos, aún no son objetos, y es por eso que C no se considera un lenguaje OOP.

    
respondido por el ryanzec 10.10.2011 - 22:49
1

Orientado a objetos se refiere tanto a un patrón arquitectónico (o incluso a un meta-patrón) y a los idiomas que tienen características para ayudar a implementar o imponer el uso de este patrón.

Puedes implementar un diseño "OO" (el escritorio de Gnome es quizás el mejor ejemplo de OO hecho en C puro), ¡incluso he visto esto hecho con COBOL!

Sin embargo, ser capaz de implementar una dosis de diseño OO no hace que el lenguaje sea OO. Los puristas argumentarían que Java y C ++ no son realmente OO, ya que no puede anular o heredar los "tipos" básicos como "int" y "char", y Java no admite la herencia múltiple. Pero como son los lenguajes OO más utilizados y son compatibles con la mayoría de los paradigmas, la mayoría de los programadores "reales" a los que se les paga para que produzcan códigos de trabajo los consideran idiomas OO.

C, por otro lado, solo admite estructuras (al igual que COBOL, Pascal y docenas de otros lenguajes de procedimiento), podría argumentar que admite la herencia múltiple, ya que puede usar cualquier función en cualquier dato, pero la mayoría considera esto como un error en lugar de una característica.

    
respondido por el James Anderson 11.10.2011 - 03:56
0

Veamos la definición de OO:

  • mensajes
  • Encapsulación
  • Encuadernación tardía

C no proporciona ninguno de esos tres. En particular, no proporciona Mensajería , que es la más importante.

    
respondido por el Jörg W Mittag 11.10.2011 - 04:00
0

Hay una serie de ingredientes clave para OO, pero los más importantes son que la mayoría del código no sabe qué hay dentro de un objeto (ven la interfaz de la superficie, no la implementación), que el estado de un objeto es una unidad administrada (es decir, cuando el objeto deja de ser, también lo hace su estado), y cuando algún código invoca una operación en un objeto, lo hace sin saber exactamente qué es o implica esa operación (todo lo que hacen es seguir un patrón para lanzar un "mensaje" sobre la pared).

C hace la encapsulación muy bien; El código que no ve la definición de una estructura no puede (legítimamente) mirar dentro de ella. Todo lo que necesita hacer es poner una definición como esta en un archivo de encabezado:

struct FooImpl;
typedef struct FooImpl *Foo;

Por supuesto, habrá una necesidad de una función que genere Foo s (es decir, una fábrica) y que deba delegar parte del trabajo al objeto asignado en sí (es decir, a través de un método "constructor"). y también para tener una forma de deshacerse del objeto nuevamente (mientras se deja que se limpie a través de su método "destructor") pero eso es un detalle.

El envío del método (es decir, la mensajería) también se puede hacer a través de la convención de que el primer elemento de la estructura es en realidad un puntero a una estructura llena de punteros de función, y que cada uno de esos punteros de función debe tomar un Foo como Su primer argumento. Luego, el envío se convierte en una cuestión de buscar la función y llamarla con la reescritura del argumento correcto, lo que no es tan difícil de hacer con un macro y un poco de astucia. (Esa tabla de funciones es el núcleo de lo que realmente es una clase en un lenguaje como C ++).

Además, eso también le da un enlace tardío: todo lo que el código de envío sabe es que está invocando un desplazamiento particular en una tabla apuntada por el objeto. Eso solo debe establecerse durante la asignación e inicialización del objeto. Es posible ir con esquemas de envío aún más complejos que le compren más dinamismo en tiempo de ejecución (a un costo de velocidad) pero son cerezas además del mecanismo básico.

Sin embargo, eso no significa que C sea un lenguaje OO. La clave es que C te deja hacer todo el trabajo difícil de escribir las convenciones y el mecanismo de envío (o utilizar una biblioteca de terceros). Eso es mucho trabajo. Tampoco proporciona soporte sintáctico o semántico, por lo que la implementación de un sistema de clase completa (con elementos como la herencia) sería innecesariamente dolorosa; Si está lidiando con un problema complejo que está bien descrito por un modelo OO, un lenguaje OO será muy útil para escribir la solución. La complejidad adicional puede ser justificada.

    
respondido por el Donal Fellows 11.10.2011 - 10:27
0

Creo que C está perfectamente bien y es decente para implementar conceptos orientados a objetos, encogiéndose de hombros . La mayoría de las diferencias, según lo veo entre el subconjunto de denominador común de lenguajes considerados orientados a objetos, son menores y de naturaleza sintáctica desde mi punto de vista pragmático.

Comencemos con, por ejemplo, ocultando información. En C podemos lograrlo simplemente ocultando la definición de una estructura y trabajando con ella a través de punteros opacos. Eso efectivamente modela la distinción public vs. private de los campos de datos a medida que obtenemos con las clases. Y es bastante fácil de hacer y apenas es anti-idiomático, ya que la biblioteca estándar de C se basa en esto para lograr el ocultamiento de la información.

Por supuesto, pierde la capacidad de controlar fácilmente dónde se asigna la estructura en la memoria usando tipos opacos, pero eso es solo una diferencia notable entre, por ejemplo, C y C ++. C ++ es definitivamente una herramienta superior cuando compara su capacidad para programar conceptos orientados a objetos sobre C mientras mantiene el control sobre los diseños de memoria, pero eso no significa necesariamente que Java o C # sea superior a C en ese sentido, ya que esos dos lo hacen pierde completamente la capacidad de controlar dónde se asignan los objetos en la memoria.

Y tenemos que usar una sintaxis como fopen(file, ...); fclose(file); en lugar de file.open(...); file.close(); pero big whoop. ¿A quien le importa? Tal vez solo alguien que se inclina fuertemente en la finalización automática en su IDE. Admito que puede ser una característica muy útil desde un punto de vista práctico, pero tal vez no sea una que requiera una discusión sobre si un idioma es adecuado para la POO.

No tenemos la capacidad de implementar efectivamente los campos protected . Me someteré totalmente allí. Pero no creo que haya una regla concreta que diga: " Todos los idiomas OO deberían tener una función para permitir que las subclases accedan a miembros de una clase base a la que aún no deberían acceder los clientes normales ". Además, rara vez veo casos de uso para miembros protegidos que no desconfían en lo más mínimo de convertirse en un obstáculo de mantenimiento.

Y, por supuesto, tenemos que "emular" el polimorfismo OO con tablas de punteros de función y punteros a ellos para un envío dinámico con un poco más de repetitivo para inicializar los analógicos vtables y vptrs , pero un poco de repetitivo nunca me causó mucho dolor.

La herencia es muy similar. Podemos modelarlo fácilmente a través de la composición, y en el funcionamiento interno de los compiladores se reduce a lo mismo. Por supuesto, perdemos la seguridad de tipos si queremos reducir , y allí diría que si quieres reducir a la baja en absoluto, por favor no utilices C porque no Las cosas que las personas hacen en C para emular a downcasting pueden ser horribles desde el punto de vista de la seguridad de tipo, pero prefiero que las personas no bajen en absoluto. La seguridad de tipos es algo que puede comenzar a perder fácilmente en C, ya que el compilador proporciona tanto margen de maniobra para interpretar las cosas como bits y bytes, sacrificando la posibilidad de detectar posibles errores en tiempo de compilación, pero algunos lenguajes considerados orientados a objetos no son ni siquiera estático.

No lo sé, creo que está bien. Por supuesto, no usaría C para intentar crear una base de código a gran escala que se ajuste a los principios de SOLID, pero no es necesariamente debido a sus limitaciones en el frente orientado a objetos. Muchas de las funciones que echaría de menos si intentara usar C para tal propósito estarían relacionadas con las características del idioma que no se consideran directamente un requisito previo para la POO, como la seguridad de tipo fuerte, los destructores que se invocan automáticamente cuando los objetos quedan fuera del alcance, el operador sobrecarga, plantillas / genéricos y manejo de excepciones. Es cuando me pierdo las funciones auxiliares que utilizo para C ++.

    
respondido por el user204677 19.12.2017 - 01:33
-1

No es una mala pregunta.

Si va a llamar a un lenguaje OO, también deberá llamar a casi todos los idiomas de procedimiento OO. Así que haría el término sin sentido. c no tiene soporte de idioma para OO. Si tiene estructuras, pero las estructuras son types no clases.

En realidad, c no tiene muchas características en comparación con la mayoría de los idiomas. Se usa principalmente por su velocidad, simplicidad, popularidad y soporte, incluidas toneladas de bibliotecas.

    
respondido por el Glen P 11.10.2011 - 10:06

Lea otras preguntas en las etiquetas