¿Cuáles son algunas formas de escribir código orientado a objetos en C? Especialmente con respecto al polimorfismo.
Véase también esta pregunta desbordamiento de pila La orientación a objetos en C .
¿Cuáles son algunas formas de escribir código orientado a objetos en C? Especialmente con respecto al polimorfismo.
Véase también esta pregunta desbordamiento de pila La orientación a objetos en C .
Respuestas:
Si. De hecho, Axel Schreiner proporciona su libro "Programación orientada a objetos en ANSI-C" de forma gratuita, que cubre el tema con bastante profundidad.
fuente
Ya que estás hablando de polimorfismo, entonces sí, puedes, estábamos haciendo ese tipo de cosas años antes de que surgiera C ++.
Básicamente, utiliza a
struct
para mantener los datos y una lista de punteros de función para apuntar a las funciones relevantes para esos datos.Por lo tanto, en una clase de comunicaciones, tendría una llamada abierta, de lectura, escritura y cierre que se mantendría como cuatro punteros de función en la estructura, junto con los datos para un objeto, algo así como:
Por supuesto, esos segmentos de código anteriores estarían realmente en un "constructor" como
rs232Init()
.Cuando 'hereda' de esa clase, simplemente cambia los punteros para señalar sus propias funciones. Todos los que llamaron a esas funciones lo harían a través de los punteros de función, dándole su polimorfismo:
Algo así como una vtable manual.
Incluso podría tener clases virtuales configurando los punteros a NULL: el comportamiento sería ligeramente diferente a C ++ (un volcado de núcleo en tiempo de ejecución en lugar de un error en tiempo de compilación).
Aquí hay un fragmento de código de muestra que lo demuestra. Primero la estructura de clase de nivel superior:
Luego tenemos las funciones para la 'subclase' de TCP:
Y el HTTP también:
Y finalmente un programa de prueba para mostrarlo en acción:
Esto produce la salida:
para que pueda ver que se llaman las diferentes funciones, dependiendo de la subclase.
fuente
tCommClass
, se cambiaría su nombretCommVT
y unatCommClass
estructura solo tendría campos de datos y un solotCommVT vt
campo que apuntara a la "única tabla virtual". Llevar todos los punteros con cada instancia agrega una sobrecarga innecesaria y se asemeja más a cómo haría cosas en JavaScript que C ++, en mi humilde opinión.Los espacios de nombres a menudo se hacen haciendo:
en vez de
Para convertir una estructura C en algo así como una clase C ++ , puede convertir:
Dentro
Y hacer:
No hice el destructor ni eliminé, pero sigue el mismo patrón.
this_is_here_as_an_example_only es como una variable de clase estática, compartida entre todas las instancias de un tipo. Todos los métodos son realmente estáticos, excepto que algunos toman esto *
fuente
st->my_type->push(st, thing2);
lugar dest->my_type.push(st, thing2);
struct stack_type my_type;
lugar destruct stack_type * my_type;
Class
estructura genérica ? Eso haría que el OO C sea más dinámico que C ++. ¿Qué hay sobre eso? Por cierto, +1.Creo que, además de ser útil por derecho propio, implementar OOP en C es una excelente manera de aprender OOP y comprender su funcionamiento interno. La experiencia de muchos programadores ha demostrado que para usar una técnica de manera eficiente y segura, un programador debe comprender cómo se implementan los conceptos subyacentes. Emular clases, herencia y polimorfismo en C enseña exactamente esto.
Para responder a la pregunta original, aquí hay un par de recursos que enseñan cómo hacer POO en C:
La publicación del blog EmbeddedGurus.com "Programación basada en objetos en C" muestra cómo implementar clases y herencia única en C portátil: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c / /
La nota de aplicación "" C + "- Programación orientada a objetos en C" muestra cómo implementar clases, herencia única y enlace tardío (polimorfismo) en C utilizando macros de preprocesador: http://www.state-machine.com/resources/cplus_3. 0_manual.pdf , el código de ejemplo está disponible en http://www.state-machine.com/resources/cplus_3.0.zip
fuente
Lo he visto hecho. No lo recomendaría C ++ originalmente comenzó de esta manera como un preprocesador que produjo código C como un paso intermedio.
Esencialmente, lo que termina haciendo es crear una tabla de despacho para todos sus métodos donde almacena sus referencias de función. Obtener una clase implicaría copiar esta tabla de despacho y reemplazar las entradas que desea anular, con sus nuevos "métodos" teniendo que llamar al método original si desea invocar el método base. Finalmente, terminas reescribiendo C ++.
fuente
glib
escrito en C de manera objetiva?Claro que es posible. Esto es lo que hace GObject , el marco en el que se basan todos los GTK + y GNOME .
fuente
La subbiblioteca C stdio FILE es un excelente ejemplo de cómo crear abstracción, encapsulación y modularidad en C. no adulterado
La herencia y el polimorfismo, los otros aspectos que a menudo se consideran esenciales para la OOP, no proporcionan necesariamente los aumentos de productividad que prometen y se han hecho argumentos razonables de que pueden obstaculizar el desarrollo y pensar sobre el dominio del problema.
fuente
Ejemplo trivial con un animal y un perro: usted refleja el mecanismo vtable de C ++ (en gran medida de todos modos) También separa la asignación y la creación de instancias (Animal_Alloc, Animal_New) para que no llamemos a malloc () varias veces. También debemos pasar explícitamente el
this
puntero.Si tuviera que hacer funciones no virtuales, eso es trivial. Simplemente no los agrega a vtable y las funciones estáticas no requieren un
this
puntero. La herencia múltiple generalmente requiere múltiples vtables para resolver ambigüedades.Además, debería poder usar setjmp / longjmp para hacer el manejo de excepciones.
PD. Esto se prueba en un compilador de C ++, pero debería ser fácil hacer que funcione en un compilador de C.
fuente
typedef
dentro de astruct
no es posible en C.Echa un vistazo a GObject . Está destinado a ser OO en C y una implementación de lo que estás buscando. Sin embargo, si realmente quieres OO, ve con C ++ o algún otro lenguaje OOP. A veces es muy difícil trabajar con GObject si estás acostumbrado a lidiar con lenguajes OO, pero como todo, te acostumbrarás a las convenciones y al flujo.
fuente
Esto ha sido interesante de leer. He estado reflexionando sobre la misma pregunta, y los beneficios de pensarlo son los siguientes:
Intentar imaginar cómo implementar conceptos de OOP en un lenguaje que no sea de OOP me ayuda a comprender las fortalezas del lenguaje de OOP (en mi caso, C ++). Esto me ayuda a juzgar mejor si usar C o C ++ para un tipo de aplicación dado, donde los beneficios de uno superan al otro.
En mi navegación por la web para obtener información y opiniones sobre esto, encontré un autor que estaba escribiendo código para un procesador incorporado y solo tenía un compilador de C disponible: http://www.eetimes.com/discussion/other/4024626/Object-Oriented -C-Creación-Fundación-Clases-Parte-1
En su caso, analizar y adaptar los conceptos de OOP en el plano C era una búsqueda válida. Parece que estaba abierto a sacrificar algunos conceptos de OOP debido al impacto en el rendimiento que resulta de intentar implementarlos en C.
La lección que he tomado es, sí, se puede hacer hasta cierto punto, y sí, hay algunas buenas razones para intentarlo.
Al final, la máquina está haciendo girar los bits del puntero de la pila, haciendo que el contador del programa salte y calculando las operaciones de acceso a la memoria. Desde el punto de vista de la eficiencia, cuantos menos cálculos realice su programa, mejor ... pero a veces tenemos que pagar este impuesto simplemente para poder organizar nuestro programa de una manera que lo haga menos susceptible al error humano. El compilador de lenguaje OOP se esfuerza por optimizar ambos aspectos. El programador debe ser mucho más cuidadoso al implementar estos conceptos en un lenguaje como C.
fuente
Puede que le resulte útil consultar la documentación de Apple para su conjunto de API de Core Foundation. Es una API de C pura, pero muchos de los tipos están unidos a equivalentes de objeto Objective-C.
También puede resultarle útil observar el diseño de Objective-C. Es un poco diferente de C ++ en que el sistema de objetos se define en términos de funciones de C, por ejemplo,
objc_msg_send
para llamar a un método en un objeto. El compilador traduce la sintaxis de corchetes en esas llamadas de función, por lo que no tiene que saberlo, pero teniendo en cuenta su pregunta, puede resultarle útil aprender cómo funciona bajo el capó.fuente
Hay varias técnicas que se pueden usar. El más importante es más cómo dividir el proyecto. Utilizamos una interfaz en nuestro proyecto que se declara en un archivo .h y la implementación del objeto en un archivo .c. La parte importante es que todos los módulos que incluyen el archivo .h ven solo un objeto como
void *
, y el archivo .c es el único módulo que conoce las internas de la estructura.Algo así para una clase que llamamos FOO como ejemplo:
En el archivo .h
El archivo de implementación C será algo así.
Entonces le doy el puntero explícitamente a un objeto para cada función de ese módulo. Un compilador de C ++ lo hace implícitamente, y en C lo escribimos explícitamente.
Realmente uso
this
en mis programas, para asegurarme de que mi programa no se compila en C ++, y tiene la excelente propiedad de estar en otro color en mi editor de resaltado de sintaxis.Los campos de FOO_struct se pueden modificar en un módulo y no es necesario volver a compilar otro módulo para poder seguir utilizándolo.
Con ese estilo ya manejo una gran parte de las ventajas de OOP (encapsulación de datos). Al usar punteros de función, incluso es fácil implementar algo como la herencia, pero honestamente, en realidad rara vez es útil.
fuente
typedef struct FOO_type FOO_type
lugar de un typedef para anular en el encabezado, obtendrá el beneficio adicional de la verificación de tipos, sin exponer su estructura.Puede simularlo utilizando punteros de función y, de hecho, creo que es teóricamente posible compilar programas C ++ en C.
Sin embargo, rara vez tiene sentido forzar un paradigma en un idioma en lugar de elegir un idioma que utilice un paradigma.
fuente
Se puede hacer C orientado a objetos, he visto ese tipo de código en producción en Corea, y fue el monstruo más horrible que había visto en años (esto fue como el año pasado (2007) cuando vi el código). Entonces sí, se puede hacer, y sí, las personas lo han hecho antes, y aún lo hacen incluso hoy en día. Pero recomendaría C ++ u Objective-C, ambos son lenguajes nacidos de C, con el propósito de proporcionar orientación a objetos con diferentes paradigmas.
fuente
Si está convencido de que un enfoque OOP es superior para el problema que está tratando de resolver, ¿por qué trataría de resolverlo con un lenguaje que no sea OOP? Parece que estás usando la herramienta incorrecta para el trabajo. Utilice C ++ o algún otro lenguaje de variantes C orientado a objetos.
Si está preguntando porque está comenzando a codificar un proyecto grande ya existente escrito en C, entonces no debe tratar de forzar sus propios paradigmas OOP (o los de cualquier otra persona) en la infraestructura del proyecto. Siga las pautas que ya están presentes en el proyecto. En general, las API limpias y bibliotecas y módulos aislados que recorrer un largo camino para tener un OOP- limpia ish diseño.
Si, después de todo esto, realmente está listo para hacer OOP C, lea esto (PDF).
fuente
Sí tu puedes. La gente escribía C orientado a objetos antes de que C ++ u Objective-C aparecieran en escena. Tanto C ++ como Objective-C fueron, en parte, intentos de tomar algunos de los conceptos de OO utilizados en C y formalizarlos como parte del lenguaje.
Aquí hay un programa realmente simple que muestra cómo puedes hacer algo que se vea como una llamada a un método (hay mejores formas de hacerlo. Esto es solo una prueba de que el lenguaje admite los conceptos):
fuente
Por supuesto, simplemente no será tan bonito como usar un lenguaje con soporte incorporado. Incluso he escrito "ensamblador orientado a objetos".
fuente
Un pequeño código OOC para agregar:
fuente
He estado cavando esto por un año:
Como el sistema GObject es difícil de usar con C puro, intenté escribir algunas buenas macros para facilitar el estilo OO con C.
Aquí está el sitio de mi proyecto (no tengo suficiente tiempo para escribir en. Doc, sin embargo, el documento en chino es mucho mejor).
OOC-GCC
fuente
Hay un ejemplo de herencia usando C en la charla de 1996 de Jim Larson dada en el Seminario de Programación de la Sección 312 a la hora del almuerzo aquí: Nivel C alto y bajo .
fuente
Las interfaces e implementaciones C de Dave Hanson son excelentes en encapsulación y denominación y muy buenas en el uso de punteros de función. Dave no intenta simular la herencia.
fuente
OOP es solo un paradigma que coloca los datos como más importantes que el código en los programas. OOP no es un idioma. Entonces, como C simple es un lenguaje simple, OOP en C simple es también simple.
fuente
Una cosa que quizás desee hacer es analizar la implementación del kit de herramientas Xt para X Window . Claro que se está alargando en el diente, pero muchas de las estructuras utilizadas fueron diseñadas para funcionar de manera OO dentro de la C. tradicional. En general, esto significa agregar una capa adicional de indirección aquí y allá y diseñar estructuras para colocarse una sobre la otra.
Realmente puedes hacer mucho en el camino de OO situado en C de esta manera, aunque a veces se siente así, los conceptos de OO no surgieron completamente de la mente
#include<favorite_OO_Guru.h>
. Realmente constituyeron muchas de las mejores prácticas establecidas de la época. Los lenguajes y sistemas OO solo destilaron y amplificaron partes del espíritu de programación del día.fuente
La respuesta a la pregunta es 'Sí, puedes'.
El kit C orientado a objetos (OOC) es para aquellos que desean programar de una manera orientada a objetos, pero también se adhiere a la buena C anterior. OOC implementa clases, herencia simple y múltiple, manejo de excepciones.
Caracteristicas
• Utiliza solo macros y funciones C, ¡no se requieren extensiones de idioma! (ANSI-C)
• Código fuente fácil de leer para su aplicación. Se tuvo cuidado de hacer las cosas lo más simples posible.
• Herencia única de clases.
• Herencia múltiple por interfaces y mixins (desde la versión 1.3)
• Implementación de excepciones (¡en C puro!)
• Funciones virtuales para clases.
• Herramienta externa para una fácil implementación de clase.
Para más detalles, visite http://ooc-coding.sourceforge.net/ .
fuente
Parece que la gente está tratando de emular el estilo C ++ usando C. Mi opinión es que al hacer programación orientada a objetos, C realmente está haciendo programación orientada a estructuras. Sin embargo, puede lograr cosas como enlace tardío, encapsulación y herencia. Para la herencia, usted define explícitamente un puntero a las estructuras base en su subestructura y obviamente esta es una forma de herencia múltiple. También deberá determinar si su
compilar con
c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj
.Por lo tanto, el consejo es mantener un estilo C puro y no tratar de forzar un estilo C ++. También de esta manera se presta a una forma muy limpia de construir una API.
fuente
Consulte http://slkpg.byethost7.com/instance.html para obtener otro giro en la OOP en C. Enfatiza los datos de instancia para la reentrada utilizando solo C. nativa La herencia múltiple se realiza manualmente utilizando envoltorios de funciones. Tipo de seguridad se mantiene. Aquí hay una pequeña muestra:
fuente
Llego un poco tarde a la fiesta, pero quiero compartir mi experiencia sobre el tema: actualmente trabajo con cosas incrustadas, y el único compilador (confiable) que tengo es C, por lo que quiero aplicar orientado a objetos enfoque en mis proyectos integrados escritos en C.
La mayoría de las soluciones que he visto hasta ahora utilizan en gran medida los tipos de letra, por lo que perdemos la seguridad de tipos: el compilador no lo ayudará si comete un error. Esto es completamente inaceptable.
Requisitos que tengo:
He explicado mi enfoque en detalle en este artículo: programación orientada a objetos en C ; Además, hay una utilidad para la autogeneración de código repetitivo para clases base y derivadas.
fuente
Construí una pequeña biblioteca donde probé eso y para mí funciona muy bien. Así que pensé en compartir la experiencia.
https://github.com/thomasfuhringer/oxygen
La herencia única se puede implementar con bastante facilidad utilizando una estructura y extendiéndola para cualquier otra clase secundaria. Una conversión simple a la estructura principal hace posible el uso de métodos principales en todos los descendientes. Siempre que sepa que una variable apunta a una estructura que contiene este tipo de objeto, siempre puede lanzar a la clase raíz y hacer introspección.
Como se ha mencionado, los métodos virtuales son algo más complicados. Pero son factibles. Para simplificar las cosas, solo uso una matriz de funciones en la estructura de descripción de clase que cada clase secundaria copia y repobla espacios individuales donde sea necesario.
La herencia múltiple sería bastante complicada de implementar y conlleva un impacto significativo en el rendimiento. Entonces lo dejo. Considero que es deseable y útil en bastantes casos modelar limpiamente las circunstancias de la vida real, pero en probablemente el 90% de los casos la herencia única cubre las necesidades. Y la herencia única es simple y no cuesta nada.
Además, no me importa la seguridad de los tipos. Creo que no debe depender del compilador para evitar errores de programación. Y de todos modos te protege de una pequeña parte de los errores.
Por lo general, en un entorno orientado a objetos, también desea implementar el recuento de referencias para automatizar la gestión de memoria en la medida de lo posible. Así que también puse un recuento de referencia en la clase raíz "Objeto" y alguna funcionalidad para encapsular la asignación y la desasignación de memoria de almacenamiento dinámico.
Todo es muy simple y delgado y me da lo esencial de OO sin obligarme a lidiar con el monstruo que es C ++. Y conservo la flexibilidad de permanecer en C land, lo que, entre otras cosas, facilita la integración de bibliotecas de terceros.
fuente
Propongo usar Objective-C, que es un superconjunto de C.
Si bien Objective-C tiene 30 años, permite escribir código elegante.
http://en.wikipedia.org/wiki/Objective-C
fuente
Sí, pero nunca he visto a nadie intentar implementar ningún tipo de polimorfismo con C.
fuente