¿Cómo se puede modelar la herencia usando C? [duplicate]

7 minutos de lectura

¿Como se puede modelar la herencia usando C duplicate
agnel kurian

¿Es posible modelar la herencia usando C? ¿Cómo? El código de muestra ayudará.

Editar: Estoy buscando heredar datos y métodos. El portacontenedores por sí solo no ayudará. Lo que necesito es la posibilidad de sustitución, usar cualquier objeto de clase derivado donde funcione un objeto de clase base.

  • ¿Cuál es la razón para hacer eso?

    – Artem Barger

    6 de agosto de 2009 a las 6:33

  • Dado que las primeras versiones de C ++ eran principalmente un preprocesador que se convertía en C, definitivamente es posible.

    – mhawke

    6 de agosto de 2009 a las 6:39

  • Tengo algo de código C que usa principalmente contenedores. El proyecto ha llegado a un punto en el que la sustituibilidad (una relación “es un”) se ha vuelto muy deseable.

    – Agnel Kurian

    6 de agosto de 2009 a las 6:47

  • básicamente responde a todas sus preguntas: http://stackoverflow.com/questions/415452/object-orientation-in-c/415536#415536

    – Junier

    6 de agosto de 2009 a las 6:48

  • Con C, puede escribir (casi) código orientado a objetos, pero no estaría fuertemente tipado.

    – Zaxter

    3 de septiembre de 2015 a las 11:46

Es muy simple ir así:

struct parent {
    int  foo;
    char *bar;
};

struct child {
    struct parent base;
    int bar;
};

struct child derived;

derived.bar = 1;
derived.base.foo = 2;

Pero si usa la extensión MS (en uso de GCC -fms-extensions bandera) puede usar anónimo anidado structs y se verá mucho mejor:

struct child {
    struct parent;    // anonymous nested struct
    int bar;
};

struct child derived;

derived.bar = 1;
derived.foo = 2;     // now it is flat

  • bien, pero ahora CLang no compilará esto …

    – makapuf

    19 de febrero de 2018 a las 21:04

  • @makapuf C11 lo admite como una característica estándar (es.wikipedia.org/wiki/…), entonces clang debe apoyarlo con -std=c11

    – qrdl

    20 de febrero de 2018 a las 6:52

  • bueno, no exactamente lo que parece. C11 lo acepta con estructuras anónimas sin etiquetar, por lo que podría incrustar otra estructura sin nombre pero no puede reutilizar una definición de estructura anterior… (por qué es el caso, no lo sé).

    – makapuf

    28 de febrero de 2018 a las 22:44

  • @makapuf sí se puede. Lo acabo de probar y puede usar estructuras definidas previamente y estructuras definidas previamente. Pero tienes que usar C11 Y la bandera, verifica gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html

    – m4l490n

    30 oct 2019 a las 16:13


¿Como se puede modelar la herencia usando C duplicate
Jérémie Koenig

Definitivamente puede escribir C en un estilo (algo) orientado a objetos.

La encapsulación se puede realizar manteniendo las definiciones de sus estructuras en el archivo .c en lugar de en el encabezado asociado. Luego, el mundo exterior maneja sus objetos manteniendo punteros hacia ellos, y usted proporciona funciones que aceptan tales punteros como los “métodos” de sus objetos.

El comportamiento similar al polimorfismo se puede obtener mediante el uso de punteros de función, generalmente agrupados dentro de “estructuras de operaciones”, algo así como la “tabla de método virtual” en sus objetos C++ (o como se llame). La estructura ops también puede incluir otras cosas, como constantes cuyo valor es específico de una “subclase” determinada. La estructura “principal” puede mantener una referencia a datos específicos de operaciones a través de un genérico void* puntero. Por supuesto, la “subclase” podría repetir el patrón para múltiples niveles de herencia.

Entonces, en el siguiente ejemplo, struct printer es similar a una clase abstracta, que se puede “derivar” completando un pr_ops estructura, y proporcionando una función constructora que envuelve pr_create(). Cada subtipo tendrá su propia estructura que estará “anclada” a la struct printer objeto a través de la data puntero genérico. Esto lo demuestra el fileprinter subtipo Uno podría imaginar una GUI o una impresora basada en socket, que sería manipulada independientemente por el resto del código como un struct printer * referencia.

impresora.h:

struct pr_ops {
    void (*printline)(void *data, const char *line);
    void (*cleanup)(void *data);
};

struct printer *pr_create(const char *name, const struct output_ops *ops, void *data);
void pr_printline(struct printer *pr, const char *line);
void pr_delete(struct printer *pr);

impresora.c:

#include "printer.h"
...

struct printer {
    char *name;
    struct pr_ops *ops;
    void *data;
}

/* constructor */
struct printer *pr_create(const char *name, const struct output_ops *ops, void *data)
{
    struct printer *p = malloc(sizeof *p);
    p->name = strdup(name);
    p->ops = ops;
    p->data = data;
}

void pr_printline(struct printer *p, const char *line)
{
    char *l = malloc(strlen(line) + strlen(p->name) + 3;
    sprintf(l, "%s: %s", p->name, line);
    p->ops->printline(p->data, l);
}

void pr_delete(struct printer *p)
{
    p->ops->cleanup(p->data);
    free(p);
}

Finalmente, fileprinter.c:

struct fileprinter {
    FILE *f;
    int doflush;
};

static void filepr_printline(void *data, const char *line)
{
    struct fileprinter *fp = data;
    fprintf(fp->f, "%s\n", line);
    if(fp->doflush) fflush(fp->f);
}

struct printer *filepr_create(const char *name, FILE *f, int doflush)
{
    static const struct ops = {
        filepr_printline,
        free,
    };

    struct *fp = malloc(sizeof *fp);
    fp->f = f;
    fp->doflush = doflush;
    return pr_create(name, &ops, fp);
}

  • +1. También como nota histórica: los primeros compiladores de C ++ no generaron código de máquina sino código C porque era más rápido y más fácil de implementar (la capa de código C a máquina existente). Entonces, definitivamente se puede hacer en C.

    – TomTom

    19 de diciembre de 2010 a las 21:01

Sí, puedes emular la herencia en C usando la técnica de “juego de palabras”. Esa es la declaración de la clase base (struct) dentro de la clase derivada, y convertir la derivada como base:

struct base_class {
  int x;
};

struct derived_class {
  struct base_class base;
  int y;
}

struct derived_class2 {
  struct base_class base;
  int z;
}
void test() {
  struct derived_class d;
  struct derived_class2 d2;

  d.base.x = 10;
  d.y = 20;

  printf("x=%i, y=%i\n", d.base.x, d.y);
}

Pero debe declarar la clase base en la primera posición en su estructura derivada, si desea convertir la derivada como base en un programa:

 struct base *b1, *b2;

 b1 = (struct base *)d;
 b2 = (struct base *)d2;

 b1->x=10;
 b2->x=20;
 printf("b1 x=%i, b2 x=%i\n", b1->x, b2->x);

En este fragmento, solo puede usar la clase base.

Yo uso esta técnica en mis proyectos: oop4c

  • ¿No debería ser &d y &d2?

    –Ajay Brahmakshatriya

    04/04/2017 a las 18:43

1647565988 45 ¿Como se puede modelar la herencia usando C duplicate
rslite

Debería ser posible, al menos hasta cierto punto.

¿Qué necesitas exactamente para modelar? ¿La herencia de los datos o de los métodos?

Editar: Aquí hay un breve artículo que encontré: http://fluff.info/blog/arch/00000162.htm

Usé un sistema de objetos en C que usaba métodos enlazados en tiempo de ejecución, lo que permitía la orientación a objetos con reflexión.

Puedes leer sobre eso aquí.

  • Por supuesto; el tema es demasiado amplio para cubrirlo completamente en una sola respuesta en stackoverflow. A primera vista, creo que el artículo vinculado a cubre mucho. Me gusta la explicación de Miro Samek en ” Practical Statecharts in C/C++” (solo 1ra edición)

    – Adrián

    6 de agosto de 2009 a las 7:02

1647565988 12 ¿Como se puede modelar la herencia usando C duplicate
Exíquilo

#include <stdio.h> 

///////Class Cobj
typedef struct Cobj{
    int x;
    void (*setptr)(char * s,int val);
    int (*getptr)(char * s);
} Cobj;

void set(char * s,int val)
{
    Cobj * y=(Cobj *)s;
    y->x=val;
}
int get(char * s){
    Cobj * y=(Cobj *)s;
    return y->x;
}
///////Class Cobj
Cobj s={12,set,get};
Cobj x;

void main(void){
    x=s;
    x.setptr((char*)&x,5);
    s.setptr((char*)&s,8);
    printf("%d %d %d",x.getptr((char*)&x),s.getptr((char*)&s) ,sizeof(Cobj));
}

  • Por supuesto; el tema es demasiado amplio para cubrirlo completamente en una sola respuesta en stackoverflow. A primera vista, creo que el artículo vinculado a cubre mucho. Me gusta la explicación de Miro Samek en ” Practical Statecharts in C/C++” (solo 1ra edición)

    – Adrián

    6 de agosto de 2009 a las 7:02

1647565989 218 ¿Como se puede modelar la herencia usando C duplicate
malayo

Este enlace puede ser útil -> Enlace

El ejemplo básico será como sigue

 struct BaseStruct
{
  // some variable
}


struct DerivedStruct
{
  struct BaseStruct lw;
  // some more variable
};

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad