una que programacion orientada objetos objeto miembros libro funciones ejemplos codigo clases clase c oop object
http://www.state-machine.com/resources/cplus_3.0.zip

que - ¿Puedes escribir código orientado a objetos en C?



programacion orientada a objetos pdf (30)

¿Puedes escribir código orientado a objetos en C? Especialmente con respecto al polimorfismo.

Consulte también la pregunta sobre el desbordamiento de pila Orientación a objetos en C.


¿Qué artículos o libros son buenos para usar conceptos de POO en C?

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.


Claro que es posible. Esto es lo que hace GObject , el marco en el que se basan todos GTK+ y GNOME .


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 individual se puede implementar con bastante facilidad utilizando una estructura y extendiéndola a todas las demás clases secundarias. Una conversión simple a la estructura principal permite utilizar 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 convertirla en la clase raíz y realizar la introspección.

Como se ha mencionado, los métodos virtuales son algo más complicados. Pero son factibles. Para mantener las cosas simples, solo uso una serie de funciones en la estructura de descripción de la clase que cada clase secundaria copia y rellena las ranuras individuales cuando sea necesario.

La herencia múltiple sería bastante complicada de implementar y tiene un impacto significativo en el rendimiento. Así que lo dejo. Considero que es deseable y útil en bastantes casos modelar con precisión las circunstancias de la vida real, pero probablemente en el 90% de los casos la herencia única cubra las necesidades. Y la herencia individual es simple y no cuesta nada.

Tampoco me importa el tipo de seguridad. Creo que no deberías depender del compilador para evitar errores de programación. Y te protege solo de una parte bastante pequeña de errores de todos modos.

Por lo general, en un entorno orientado a objetos, también desea implementar el conteo de referencias para automatizar la administración de la 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 la memoria del montón.

Todo es muy simple y magro 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.


Consulte http://slkpg.byethost7.com/instance.html para ver otro giro en la POO en C. Enfatiza los datos de instancia para reentrancia usando solo la C. nativa. La herencia múltiple se realiza manualmente usando envoltorios de funciones. Se mantiene el tipo de seguridad. Aquí hay una pequeña muestra:

typedef struct _peeker { log_t *log; symbols_t *sym; scanner_t scan; // inherited instance peek_t pk; int trace; void (*push) ( SELF *d, symbol_t *symbol ); short (*peek) ( SELF *d, int level ); short (*get) ( SELF *d ); int (*get_line_number) ( SELF *d ); } peeker_t, SlkToken; #define push(self,a) (*self).push(self, a) #define peek(self,a) (*self).peek(self, a) #define get(self) (*self).get(self) #define get_line_number(self) (*self).get_line_number(self) INSTANCE_METHOD int (get_line_number) ( peeker_t *d ) { return d->scan.line_number; } PUBLIC void InitializePeeker ( peeker_t *peeker, int trace, symbols_t *symbols, log_t *log, list_t *list ) { InitializeScanner ( &peeker->scan, trace, symbols, log, list ); peeker->log = log; peeker->sym = symbols; peeker->pk.current = peeker->pk.buffer; peeker->pk.count = 0; peeker->trace = trace; peeker->get_line_number = get_line_number; peeker->push = push; peeker->get = get; peeker->peek = peek; }


Creo que además de ser útil por derecho propio, la implementación de la POO en C es una excelente manera de aprender la POO y comprender su funcionamiento interno. La experiencia de muchos programadores ha demostrado que para utilizar una técnica de manera eficiente y segura, un programador debe comprender cómo se implementan finalmente los conceptos subyacentes. Emular clases, herencia y polimorfismo en C enseña esto.

Para responder a la pregunta original, aquí hay un par de recursos que enseñan cómo hacer la POO en C:

La publicación del blog de 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/

Nota de aplicación "" C + ": la programación orientada a objetos en C" muestra cómo implementar clases, herencia única y enlace tardío (polimorfismo) en C mediante 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


Echa un vistazo a GObject . Está destinado a ser OO en C y una implementación de lo que está buscando. Si realmente quieres OO, ve con C ++ o algún otro lenguaje OOP. Puede ser muy difícil trabajar con GObject a veces si está acostumbrado a tratar con idiomas OO, pero como cualquier cosa, se acostumbrará a las convenciones y al flujo.


Ejemplo trivial con un animal y un perro: reflejas 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), por lo que no llamamos a malloc () varias veces. También debemos pasar explícitamente this puntero alrededor.

Si fueras a hacer funciones no virtuales, eso es trival. Simplemente no los agrega a las funciones vtable y las funciones estáticas no requieren 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.

struct Animal_Vtable{ typedef void (*Walk_Fun)(struct Animal *a_This); typedef struct Animal * (*Dtor_Fun)(struct Animal *a_This); Walk_Fun Walk; Dtor_Fun Dtor; }; struct Animal{ Animal_Vtable vtable; char *Name; }; struct Dog{ Animal_Vtable vtable; char *Name; // Mirror member variables for easy access char *Type; }; void Animal_Walk(struct Animal *a_This){ printf("Animal (%s) walking/n", a_This->Name); } struct Animal* Animal_Dtor(struct Animal *a_This){ printf("animal::dtor/n"); return a_This; } Animal *Animal_Alloc(){ return (Animal*)malloc(sizeof(Animal)); } Animal *Animal_New(Animal *a_Animal){ a_Animal->vtable.Walk = Animal_Walk; a_Animal->vtable.Dtor = Animal_Dtor; a_Animal->Name = "Anonymous"; return a_Animal; } void Animal_Free(Animal *a_This){ a_This->vtable.Dtor(a_This); free(a_This); } void Dog_Walk(struct Dog *a_This){ printf("Dog walking %s (%s)/n", a_This->Type, a_This->Name); } Dog* Dog_Dtor(struct Dog *a_This){ // Explicit call to parent destructor Animal_Dtor((Animal*)a_This); printf("dog::dtor/n"); return a_This; } Dog *Dog_Alloc(){ return (Dog*)malloc(sizeof(Dog)); } Dog *Dog_New(Dog *a_Dog){ // Explict call to parent constructor Animal_New((Animal*)a_Dog); a_Dog->Type = "Dog type"; a_Dog->vtable.Walk = (Animal_Vtable::Walk_Fun) Dog_Walk; a_Dog->vtable.Dtor = (Animal_Vtable::Dtor_Fun) Dog_Dtor; return a_Dog; } int main(int argc, char **argv){ /* Base class: Animal *a_Animal = Animal_New(Animal_Alloc()); */ Animal *a_Animal = (Animal*)Dog_New(Dog_Alloc()); a_Animal->vtable.Walk(a_Animal); Animal_Free(a_Animal); }

PD. Esto se prueba en un compilador de C ++, pero debería ser fácil hacerlo funcionar en un compilador de C.


Es posible que desee hacer algo al analizar la implementación del kit de herramientas Xt para X Window . Claro que se está haciendo largo en el diente, pero muchas de las estructuras utilizadas fueron diseñadas para funcionar de manera OO dentro de la C tradicional. Generalmente, esto significa agregar una capa adicional de direccionamiento indirecto aquí y allá y diseñar estructuras para que se apoyen unas sobre otras.

Realmente puedes hacer mucho en el camino de OO situado en C de esta manera, aunque parece que algunas veces, los conceptos de OO no surgieron completamente de la mente de #include<favorite_OO_Guru.h> . Realmente constituían muchas de las mejores prácticas establecidas de la época. OO lenguajes y sistemas solo partes destiladas y amplificadas de la zeitgeist de programación del día.


Esto ha sido interesante de leer. Yo mismo he estado reflexionando sobre la misma pregunta, y los beneficios de pensar en esto son los siguientes:

  • Tratar de imaginar cómo implementar conceptos OOP en un lenguaje que no sea OOP me ayuda a comprender las fortalezas del lenguaje OOp (en mi caso, C ++). Esto me ayuda a tener un mejor criterio acerca de si usar C o C ++ para un tipo dado de aplicación, 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 integrado y solo tenía un compilador de C disponible: http://www.eetimes.com/discussion/other/4024626/Object-Oriented-C-Creating-Foundation-Classes-Part-1

En su caso, el análisis y la adaptación de los conceptos de OOP en C simple fue una búsqueda válida. Parece que estaba dispuesto a sacrificar algunos conceptos OOP debido a la sobrecarga en el rendimiento resultante del intento de implementarlos en C.

La lección que tomé es, sí, se puede hacer hasta cierto punto, y sí, hay algunas buenas razones para intentarlo.

Al final, la máquina está girando los bits de puntero de la pila, haciendo que el contador del programa salte y calcule 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 que podamos 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.



Hay varias técnicas que se pueden utilizar. 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 solo ven un objeto como un void * , y el archivo .c es el único módulo que conoce las partes internas de la estructura.

Algo como esto para una clase que llamamos FOO como ejemplo:

En el archivo .h

#ifndef FOO_H_ #define FOO_H_ ... typedef struct FOO_type FOO_type; /* That''s all the rest of the program knows about FOO */ /* Declaration of accessors, functions */ FOO_type *FOO_new(void); void FOO_free(FOO_type *this); ... void FOO_dosomething(FOO_type *this, param ...): char *FOO_getName(FOO_type *this, etc); #endif

El archivo de implementación de C será algo así.

#include <stdlib.h> ... #include "FOO.h" struct FOO_type { whatever... }; FOO_type *FOO_new(void) { FOO_type *this = calloc(1, sizeof (FOO_type)); ... FOO_dosomething(this, ); return this; }

Así que 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 compile en C ++, y tiene la propiedad de estar en otro color en mi editor de resaltado de sintaxis.

Los campos de la FOO_struct se pueden modificar en un módulo y otro módulo ni siquiera necesita volver a compilarse para seguir utilizándose.

Con ese estilo, ya manejo gran parte de las ventajas de la POO (encapsulación de datos). Mediante el uso de punteros de función, incluso es fácil implementar algo como la herencia, pero honestamente, rara vez es útil.


He estado cavando esto durante un año:

Como el sistema GObject es difícil de usar con C pura, traté de escribir algunas macros agradables para facilitar el estilo OO con C.

#include "OOStd.h" CLASS(Animal) { char *name; STATIC(Animal); vFn talk; }; static int Animal_load(Animal *THIS,void *name) { THIS->name = name; return 0; } ASM(Animal, Animal_load, NULL, NULL, NULL) CLASS_EX(Cat,Animal) { STATIC_EX(Cat, Animal); }; static void Meow(Animal *THIS){ printf("Meow!My name is %s!/n", THIS->name); } static int Cat_loadSt(StAnimal *THIS, void *PARAM){ THIS->talk = (void *)Meow; return 0; } ASM_EX(Cat,Animal, NULL, NULL, Cat_loadSt, NULL) CLASS_EX(Dog,Animal){ STATIC_EX(Dog, Animal); }; static void Woof(Animal *THIS){ printf("Woof!My name is %s!/n", THIS->name); } static int Dog_loadSt(StAnimal *THIS, void *PARAM) { THIS->talk = (void *)Woof; return 0; } ASM_EX(Dog, Animal, NULL, NULL, Dog_loadSt, NULL) int main(){ Animal *animals[4000]; StAnimal *f; int i = 0; for (i=0; i<4000; i++) { if(i%2==0) animals[i] = NEW(Dog,"Jack"); else animals[i] = NEW(Cat,"Lily"); }; f = ST(animals[0]); for(i=0; i<4000; ++i) { f->talk(animals[i]); } for (i=0; i<4000; ++i) { DELETE0(animals[i]); } return 0; }

Aquí está el sitio de mi proyecto (no tengo tiempo suficiente para escribir en. Doc, sin embargo, el documento en chino es mucho mejor).

OOC-GCC


La POO es solo un paradigma que coloca los datos como más importantes que el código en los programas. OOP no es un lenguaje. Por lo tanto, al igual que C simple es un lenguaje simple, OOP en C simple también es simple.


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 apega a la buena C antigua. OOC implementa clases, herencia única y múltiple, manejo de excepciones.

Caracteristicas

• Utiliza solo macros C y funciones, no requiere extensiones de lenguaje! (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)

• Implementando excepciones (en puro C!)

• Funciones virtuales para las clases.

• Herramienta externa para una fácil implementación en clase.

Para obtener más detalles, visite http://ooc-coding.sourceforge.net/ .


La sub-biblioteca C stdio FILE es un excelente ejemplo de cómo crear abstracción, encapsulación y modularidad en C no adulterada.

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 presentado arguments reasonable que en realidad pueden obstaculizar el desarrollo y pensar sobre el dominio del problema.


Llego un poco tarde a la fiesta, pero quiero compartir mi experiencia sobre el tema: trabajo con cosas incrustadas en estos días, y el único compilador (confiable) que tengo es C, por lo que quiero aplicar la orientación a objetos. Enfoque en mis proyectos incrustados escritos en C.

La mayoría de las soluciones que he visto hasta ahora utilizan las tipografías en gran medida, por lo que perdemos la seguridad de tipos: el compilador no lo ayudará si comete un error. Esto es completamente inaceptable.

Requisitos que tengo:

  • Evite las tipificaciones lo más posible, para no perder la seguridad de los tipos;
  • Polimorfismo: deberíamos poder usar métodos virtuales, y el usuario de la clase no debe saber si algún método en particular es virtual o no;
  • Herencia múltiple: no la uso a menudo, pero a veces realmente quiero que alguna clase implemente múltiples interfaces (o que extienda múltiples superclases).

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.


Lo he visto hecho. Yo no lo recomendaría. C ++ originalmente comenzó de esta manera como un preprocesador que producía el código C como un paso intermedio.

Esencialmente, lo que terminas haciendo es crear una tabla de despacho para todos tus métodos donde almacenes tus referencias de funciones. Derivar una clase implicaría copiar esta tabla de despacho y reemplazar las entradas que deseaba anular, y sus nuevos "métodos" tendrán que llamar al método original si desean invocar el método base. Finalmente, terminas reescribiendo C ++.


Los espacios de nombres se hacen a menudo haciendo:

stack_push(thing *)

en lugar de

stack::push(thing *)

Para convertir una estructura de C en algo como una clase de C++ , puede convertir:

class stack { public: stack(); void push(thing *); thing * pop(); static int this_is_here_as_an_example_only; private: ... };

Dentro

struct stack { struct stack_type * my_type; // Put the stuff that you put after private: here }; struct stack_type { void (* construct)(struct stack * this); // This takes uninitialized memory struct stack * (* operator_new)(); // This allocates a new struct, passes it to construct, and then returns it void (*push)(struct stack * this, thing * t); // Pushing t onto this stack thing * (*pop)(struct stack * this); // Pops the top thing off the stack and returns it int this_is_here_as_an_example_only; }Stack = { .construct = stack_construct, .operator_new = stack_operator_new, .push = stack_push, .pop = stack_pop }; // All of these functions are assumed to be defined somewhere else

Y hacer:

struct stack * st = Stack.operator_new(); // Make a new stack if (!st) { // Do something about it } else { // You can use the stack stack_push(st, thing0); // This is a non-virtual call Stack.push(st, thing1); // This is like casting *st to a Stack (which it already is) and doing the push st->my_type.push(st, thing2); // This is a virtual call }

No hice el destructor ni lo 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 *


Parece que la gente está tratando de emular el estilo C ++ usando C. Mi opinión es que hacer programación orientada a objetos C realmente está haciendo programación orientada a estructuras. Sin embargo, puede lograr cosas como la vinculación tardía, la encapsulación y la herencia. Para la herencia, explícitamente define un puntero a las estructuras base en su estructura secundaria y esto obviamente es una forma de herencia múltiple. También deberá determinar si su

//private_class.h struct private_class; extern struct private_class * new_private_class(); extern int ret_a_value(struct private_class *, int a, int b); extern void delete_private_class(struct private_class *); void (*late_bind_function)(struct private_class *p); //private_class.c struct inherited_class_1; struct inherited_class_2; struct private_class { int a; int b; struct inherited_class_1 *p1; struct inherited_class_2 *p2; }; struct inherited_class_1 * new_inherited_class_1(); struct inherited_class_2 * new_inherited_class_2(); struct private_class * new_private_class() { struct private_class *p; p = (struct private_class*) malloc(sizeof(struct private_class)); p->a = 0; p->b = 0; p->p1 = new_inherited_class_1(); p->p2 = new_inherited_class_2(); return p; } int ret_a_value(struct private_class *p, int a, int b) { return p->a + p->b + a + b; } void delete_private_class(struct private_class *p) { //release any resources //call delete methods for inherited classes free(p); } //main.c struct private_class *p; p = new_private_class(); late_bind_function = &implementation_function; delete_private_class(p);

compilar con c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj .

Entonces, el consejo es seguir un estilo C puro y no intentar forzar un estilo C ++. También de esta manera se presta a una forma muy limpia de construir una API.


Por supuesto, no será tan bonito como usar un lenguaje con soporte incorporado. Incluso he escrito "ensamblador orientado a objetos".


Puede resultarle útil consultar la documentación de Apple para el conjunto de API de Core Foundation. Es una API de C pura, pero muchos de los tipos están enlazados a los equivalentes de objetos de Objective-C.

También puede resultarle útil ver el diseño de Objective-C en sí. 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 del corchete en esas llamadas de función, por lo que no tiene que saberlo, pero considerando su pregunta, puede que le resulte útil aprender cómo funciona bajo el capó.


Puedes falsificarlo utilizando punteros de función, y de hecho, creo que teóricamente es 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 usa un paradigma.


Sí tu puedes. Las personas escribían C orientado a objetos antes de que C ++ o Objective-C entraran en escena. Tanto C ++ como Objective-C fueron, en parte, intentos de tomar algunos de los conceptos OO utilizados en C y formalizarlos como parte del lenguaje.

Aquí hay un programa realmente simple que muestra cómo puede hacer algo que se parece a / es una llamada de método (hay mejores formas de hacerlo. Esto es solo una prueba de que el lenguaje es compatible con los conceptos):

#include<stdio.h> struct foobarbaz{ int one; int two; int three; int (*exampleMethod)(int, int); }; int addTwoNumbers(int a, int b){ return a+b; } int main() { // Define the function pointer int (*pointerToFunction)(int, int) = addTwoNumbers; // Let''s make sure we can call the pointer int test = (*pointerToFunction)(12,12); printf ("test: %u /n", test); // Now, define an instance of our struct // and add some default values. struct foobarbaz fbb; fbb.one = 1; fbb.two = 2; fbb.three = 3; // Now add a "method" fbb.exampleMethod = addTwoNumbers; // Try calling the method int test2 = fbb.exampleMethod(13,36); printf ("test2: %u /n", test2); printf("/nDone/n"); return 0; }


Sí. De hecho, Axel Schreiner proporciona su libro "Programación orientada a objetos en ANSI-C" de forma gratuita, que cubre el tema con bastante detalle.


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) que vi el código). Entonces sí, se puede hacer, y sí, las personas lo han hecho antes, y aún lo hacen incluso en estos tiempos. Pero recomendaría C ++ o Objective-C, ambos son lenguajes nacidos de C, con el propósito de proporcionar orientación a objetos con diferentes paradigmas.


Si está convencido de que un enfoque OOP es superior para el problema que está tratando de resolver, ¿por qué intentaría resolverlo con un lenguaje que no sea OOP? Parece que estás usando la herramienta incorrecta para el trabajo. Use C ++ o algún otro lenguaje de variante C orientado a objetos.

Si está preguntando porque está empezando a codificar en un proyecto grande ya existente escrito en C, no debe intentar forzar sus propios paradigmas de POO (o los de cualquier otra persona) en la infraestructura del proyecto. Sigue las pautas que ya están presentes en el proyecto. En general, las API limpias y las bibliotecas y módulos aislados contribuirán en gran medida a tener un diseño de OOPsis limpio.

Si, después de todo esto, realmente estás listo para hacer OOP C, lee esto (PDF).


Un pequeño código OOC para agregar:

#include <stdio.h> struct Node { int somevar; }; void print() { printf("Hello from an object-oriented C method!"); }; struct Tree { struct Node * NIL; void (*FPprint)(void); struct Node *root; struct Node NIL_t; } TreeA = {&TreeA.NIL_t,print}; int main() { struct Tree TreeB; TreeB = TreeA; TreeB.FPprint(); return 0; }


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, se usa una struct para contener tanto los datos como una lista de punteros de función para señalar las funciones relevantes para esos datos.

Entonces, 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 de un objeto, algo como:

typedef struct { int (*open)(void *self, char *fspec); int (*close)(void *self); int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz); int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz); // And data goes here. } tCommClass; tCommClass commRs232; commRs232.open = &rs232Open; : : commRs232.write = &rs232Write; tCommClass commTcp; commTcp.open = &tcpOpen; : : commTcp.write = &tcpWrite;

Por supuesto, los segmentos de código anteriores estarían en realidad en un "constructor" como rs232Init() .

Cuando "hereda" de esa clase, simplemente cambia los punteros para que apunten a 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:

int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");

Algo así como un manual vtable.

Incluso podría tener clases virtuales estableciendo los punteros en 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 una pieza de código de muestra que lo demuestra. Primero la estructura de clase de nivel superior:

#include <stdio.h> // The top-level class. typedef struct sCommClass { int (*open)(struct sCommClass *self, char *fspec); } tCommClass;

Luego tenemos las funciones para la ''subclase'' de TCP:

// Function for the TCP ''class''. static int tcpOpen (tCommClass *tcp, char *fspec) { printf ("Opening TCP: %s/n", fspec); return 0; } static int tcpInit (tCommClass *tcp) { tcp->open = &tcpOpen; return 0; }

Y el HTTP también:

// Function for the HTTP ''class''. static int httpOpen (tCommClass *http, char *fspec) { printf ("Opening HTTP: %s/n", fspec); return 0; } static int httpInit (tCommClass *http) { http->open = &httpOpen; return 0; }

Y finalmente un programa de prueba para mostrarlo en acción:

// Test program. int main (void) { int status; tCommClass commTcp, commHttp; // Same ''base'' class but initialised to different sub-classes. tcpInit (&commTcp); httpInit (&commHttp); // Called in exactly the same manner. status = (commTcp.open)(&commTcp, "bigiron.box.com:5000"); status = (commHttp.open)(&commHttp, "http://www.microsoft.com"); return 0; }

Esto produce la salida:

Opening TCP: bigiron.box.com:5000 Opening HTTP: http://www.microsoft.com

para que pueda ver que las diferentes funciones están siendo llamadas, dependiendo de la subclase.


Propongo usar Objective-C, que es un superconjunto de C.

Mientras que Objective-C tiene 30 años, permite escribir código elegante.

Objective-C


Sí, pero nunca he visto a nadie intentar implementar ningún tipo de polimorfismo con C.