2010-11-05 25 views
5

Duplicar posible:
Can you write object oriented code in C?experimento: orientado a objetos C?

Hola!

Por el gusto de hacerlo, he estado experimentando estos dos últimos días creando un entorno de objetos muy sencillo y muy sencillo en C. puro. He estado jugando con macros, enlaces dinámicos, estructuras de descripción de tipos y similares, y he llegado a la siguiente:

string_o str = new(String, "hello world"); 
list_o list = new(List); 

List.pushf(list, str); 

printf("In the list: \"%s\"\n", 
     String.text(List.popf(list))); 

delete(list); 
delete(str); 

se ve y funciona un poco agradable, pero no puedo imaginar una forma de métodos de instancia falsos. No puedo pasar Class.function(instance), no sin macro reemplazos globales para los nombres de funciones, lo que frustra el propósito de la encapsulación.

De nuevo, este es un experimento, solo por el desafío y la diversión =). ¿Pueden ayudarme a encontrar una manera de hacer esto? No quiero usar preprocesamiento adicional, solo macros simples C y GCC.

editar> se olvidó de decir: no quiero que cada instancia contenga los punteros a función en su estructura. Eso me daría la sintaxis del método bien, pero significaría que un objeto de datos de 4 bytes tendría una docena de punteros de función copiados en cada instancia. Eso es como hacer trampa = P haha ​​

¡Gracias de antemano!

+3

¿no es eso por lo que crearon cpp?: P – Tobias

+3

Asociar cada 'clase' con una tabla de punteros de función que se ejecutan cuando se llama a una 'función de miembro'? – birryree

+0

@Tobias: _shudder_, ¡espero que no! [C++: un pulpo hecho clavando patas adicionales en un perro.] (Http://en.wikiquote.org/wiki/Programming_languages#C.2FC.2B.2B) - Steve Taylor: P –

Respuesta

12

La orientación del objeto en C normalmente se realiza con punteros a funciones. Eso significa una estructura que contiene no solo los datos de una instancia sino también las funciones a llamar.

Es la forma más fácil de heredar y polimorfismo en C. A modo de ejemplo, aquí hay un ejemplo de comunicación orientada a objetos.

Solo tiene un método open, pero puede ver cómo eso difiere para las subclases TCP y HTML. Al tener una rutina de inicialización que establece una función específica de clase, obtienes polimorfismo.

#include <stdio.h> 

// The top-level class. 

typedef struct _tCommClass { 
    int (*open)(struct _tCommClass *self, char *fspec); 
} tCommClass; 

// 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; 
} 

// Function for the HTML class. 

static int htmlOpen (tCommClass *html, char *fspec) { 
    printf ("Opening HTML: %s\n", fspec); 
    return 0; 
} 
static int htmlInit (tCommClass *html) { 
    html->open = &htmlOpen; 
    return 0; 
} 

// Test program. 

int main (void) { 
    int status; 
    tCommClass commTcp, commHtml; 

    // Same base class but initialized to different sub-classes. 
    tcpInit (&commTcp); 
    htmlInit (&commHtml); 

    // Called in exactly the same manner. 

    status = (commTcp.open)(&commTcp, "bigiron.box.com:5000"); 
    status = (commHtml.open)(&commHtml, "http://www.microsoft.com"); 

    return 0; 
} 

Una respuesta más completa se puede encontrar here.

En respuesta a tu comentario:

no quiero las funciones contenidas en cada instancia.

Probablemente tenga razón. No es necesario duplicar esa información cuando será la misma para cada instancia de una sola clase.

Hay una manera simple de evitarlo. En lugar de hacer que cada instancia lleve su propio conjunto de indicadores de función, se crea una estructura que los mantiene para la clase, luego cada instancia obtiene un puntero a esa estructura.

Eso ahorrará bastante espacio al costo (mínimo) de tener que hacer dos niveles de direccionamiento indirecto para llamar a una función.

+0

Gracias por la respuesta, pero olvidé decir, no quiero las funciones que figuran en cada instancia. ¡Imagínese si cada nodo de lista, entero envuelto o lo que sea, tuviera que contener 20 punteros de función! – slezica

+1

Bueno, entonces podría tener un puntero _single_ en la estructura que apuntaba a una matriz de punteros de función específica de la clase. Tendrías que usar el doble direccionamiento indirecto para llamar a las funciones en lugar de direccionamiento único, pero te ahorraría el espacio. Añadiré eso a mi respuesta. – paxdiablo

+0

Lo siento, ¡acabo de leer eso! Sí, no me preocupa ser * incapaz * de alcanzar las funciones. Podría hacerlo (supongamos que un puntero a la clase en el objeto se llama 'f') object-> f-> fun (object); pero se ve feo como el infierno jajaja. Estoy intentando hacer una macro hasta object.fun(); - No sé si es posible en absoluto. – slezica

Cuestiones relacionadas