Creo que C está perfectamente bien y decente para implementar conceptos orientados a objetos, encogerse de hombros . La mayoría de las diferencias, según lo veo, entre el subconjunto común de denominadores de lenguajes considerados orientados a objetos son menores y de naturaleza sintáctica desde mi punto de vista pragmático.
Comencemos con, digamos, ocultar información. En C podemos lograr eso simplemente ocultando la definición de una estructura y trabajando con ella a través de punteros opacos. Eso modela efectivamente la distinción public
vs. private
los campos de datos a medida que lo hacemos con las clases. Y es bastante fácil de hacer y apenas anti-idiomático, ya que la biblioteca C estándar se basa en gran medida en esto para lograr ocultar la información.
Por supuesto, pierde la capacidad de controlar fácilmente exactamente dónde se asigna la estructura en la memoria mediante el uso de tipos opacos, pero eso es solo una diferencia notable entre, por ejemplo, C y C ++. C ++ es definitivamente una herramienta superior cuando se compara su capacidad para programar conceptos orientados a objetos sobre C mientras se mantiene el control sobre los diseños de memoria, pero eso no significa necesariamente que Java o C # sean superiores a C en ese sentido, ya que esos dos te hacen pierde por completo 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 un file.open(...); file.close();
gran whoop. ¿A quien le importa? Tal vez solo alguien que se apoya mucho en la autocompletación en su IDE. Admito que puede ser una característica muy útil desde un punto de vista práctico, pero tal vez no una que requiera una discusión sobre si un lenguaje es adecuado para la POO.
Carecemos de la capacidad de implementar efectivamente los protected
campos. Me someteré totalmente allí. Pero no creo que haya una regla concreta que diga: " Todos los lenguajes OO deberían tener una función que permita a las subclases acceder a miembros de una clase base a la que los clientes normales aún no deberían tener acceso ". Además, rara vez veo casos de uso para miembros protegidos que no son al menos un poco sospechosos 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 para enviarlos dinámicamente con un poco más de repetitivo para inicializar aquellos analógicos vtables
y vptrs
, pero un poco de repetitivo nunca me causó mucho dolor.
La herencia es muy parecida. 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 los tipos si queremos hacer downcast , y diría que si quieres hacer downcasts , no uses C para eso porque las cosas que las personas hacen en C para emular el downcast pueden ser horribles por un tipo punto de vista de seguridad, pero prefiero que la gente no se desanime en absoluto. La seguridad de tipos es algo que puede comenzar a pasar por alto fácilmente en C, ya que el compilador proporciona tanta libertad para interpretar cosas como solo bits y bytes, sacrificando la capacidad de detectar posibles errores en tiempo de compilación, pero algunos lenguajes considerados no están orientados a objetos ni siquiera estáticamente escrito.
No 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 SÓLIDOS, pero no necesariamente se debe a sus defectos en el frente orientado a objetos. Muchas de las características que extrañaría si intentara usar C para tal fin estarían relacionadas con las características del lenguaje que no se consideran directamente un requisito previo para la POO, como la seguridad de tipo fuerte, destructores que se invocan automáticamente cuando los objetos están fuera de alcance, operador sobrecarga, plantillas / genéricos y manejo de excepciones. Es cuando me faltan esas características auxiliares que alcanzo para C ++.