Como Pode a herança ser modelada usando C? [duplicado]

[[2] esta pergunta já tem uma resposta aqui:

É possível modelar a herança usando C? Como? O código da amostra vai ajudar.

Edit: estou a tentar herdar tanto os dados como os métodos. Conter sozinho não vai ajudar. Substituibilidade-utilizando qualquer objecto de classe derivada em que a objeto de classe base funciona-é o que eu preciso.

Author: Agnel Kurian, 2009-08-06

8 answers

É muito simples fazer assim:

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

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

struct child derived;

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

Mas se usar a extensão MS (na opção GCC -fms-extensions pode usar anônimos aninhados struct e ficará muito melhor:

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

struct child derived;

derived.bar = 1;
derived.foo = 2;     // now it is flat
 21
Author: qrdl, 2009-08-06 06:42:34

Você pode definitivamente escrever C em um estilo (um pouco) orientado a objetos.

Encapsulamento pode ser feito mantendo as definições das suas estruturas no .C file rather than in the associated header. Então o mundo exterior lida com os seus objectos, mantendo-os apontados para eles., e você fornece funções que aceitam ponteiros como os"métodos" dos seus objectos.

O Comportamento de polimorfismo pode ser obtido usando ponteiros de funções, normalmente agrupados dentro das " operações estrutura", como a "tabela de método virtual" nos seus objectos em C++ (ou seja lá como se chama). A estrutura dos PO também pode incluir outras coisas, tais como: constantes cujo valor é específico a uma dada "subclasse". A estrutura " pai " pode manter uma referência a dados específicos da ops através de um indicador Genérico void*. É claro que a "subclasse" poderia repetir o padrão para vários níveis de herança.

Assim, no exemplo abaixo, {[4] } é semelhante a uma classe abstrata, que pode ser "derivado" por preencher uma estrutura pr_ops, e fornecendo um invólucro de funções de construção pr_create(). Cada subtipo terá a sua própria estrutura que será "ancorada" para o objecto struct printer através do ponteiro Genérico data. Isto é demonstrado pelo subtipo fileprinter. Pode-se imaginar uma impressora GUI ou socket-based, isso seria manipulado independentemente do resto do Código. como referência.

Impressora.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);

Impressora.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);
}
 8
Author: Jérémie Koenig, 2011-05-28 18:50:32

Deve ser possível, pelo menos em certa medida.

O que precisas de modelar? A herança dos dados ou os métodos?

Editar : aqui está um pequeno artigo que encontrei: http://fluff.info/blog/arch/00000162.htm

 3
Author: rslite, 2009-08-06 06:40:44
Sim, podes emular heritância en C usando a técnica do "tipo punning". Esta é a declaração da classe de base (struct) dentro da classe derivada, e moldar a derivada como uma 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);
}

Mas você deve declarar a classe base na primeira posição na sua estrutura derivada, se você quiser lançar a derivada como base em um 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);

Neste excerto pode usar apenas a classe base.

Uso esta técnica nos meus projectos: oop4c

 3
Author: curif, 2014-07-18 11:54:51

Uma vez que as primeiras versões de C++ eram principalmente um pré-processador que se converteu em C, é deinitely possível.

 2
Author: mhawke, 2009-08-06 06:39:57

Usei um sistema de objectos em C que usou métodos de limite tardio, o que permitiu orientação de objectos com reflexão.

Você pode ler sobre isso aqui .

 2
Author: Ryan Fox, 2009-08-06 06:56:55

Esta ligação pode ser útil - > ligação

O exemplo básico será como seguir

 struct BaseStruct
{
  // some variable
}


struct DerivedStruct
{
  struct BaseStruct lw;
  // some more variable
};
 1
Author: malay, 2009-08-06 06:36:39
#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));
}
 1
Author: Raks, 2015-03-19 04:24:25