Подтвердить что ты не робот

Как можно наследовать, используя C?

Можно ли моделировать наследование с помощью C? Как? Пример кода поможет.

Изменить: Я ищу наследование как данных, так и методов. Контейнеры сами по себе не помогут. Подстановка - использование любого объекта производного класса, где работает объект базового класса, - это то, что мне нужно.

4b9b3361

Ответ 1

Очень просто сделать следующее:

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

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

struct child derived;

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

Но если вы используете расширение MS (в GCC используйте флаг -fms-extensions), вы можете использовать анонимный вложенный struct, и он будет выглядеть намного лучше:

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

struct child derived;

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

Ответ 2

Вы можете определенно написать C в (несколько) объектно-ориентированном стиле.

Инкапсуляция может быть выполнена путем хранения определений ваших структур в .c файле, а не в соответствующем заголовке. Затем внешний мир обрабатывает ваши объекты, удерживая указатели на них, и вы предоставляете функции, принимающие такие указатели, как "методы", ваших объектов.

Поведение, подобное полиморфизму, может быть получено с помощью указателей функций, обычно сгруппированные в "операционные структуры", вроде "таблицы виртуальных методов" в ваших объектах С++ (или как он там называется). Структура ops может также включать другие вещи, такие как константы, значение которых специфично для данного "подкласса". "Родительская" структура может содержать ссылку на данные, специфичные для ops через общий указатель void*. Конечно, "подкласс" мог бы повторить шаблон для нескольких уровней наследования.

Итак, в приведенном ниже примере struct printer сродни абстрактному классу, который может быть "получен" путем заполнения структуры pr_ops и предоставление функции конструктора pr_create(). Каждый подтип будет иметь свою собственную структуру, которая будет "закреплена", к объекту struct printer через общий указатель data. Это демотируется подтипом fileprinter. Можно представить графический интерфейс или принтер на основе сокетов, которые будут обрабатываться независимо от остальной части кода в качестве ссылки struct printer *.

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

printer.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);
}

Наконец, 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);
}

Ответ 3

Это должно быть возможно, по крайней мере, в некоторой степени.

Что именно вам нужно моделировать? Наследование данных или методов?

Изменить. Вот короткая статья, которую я нашел: http://fluff.info/blog/arch/00000162.htm

Ответ 4

Так как ранние версии С++ были в основном препроцессором, который преобразовывался в C, это было бы возможно.

Ответ 5

Я использовал объектную систему в C, которая использовала поздние методы, что позволяло объектно-ориентированную ориентацию с отражением.

Вы можете прочитать об этом здесь.

Ответ 6

Эта ссылка может быть полезна → ссылка

Основной пример будет выглядеть следующим образом

 struct BaseStruct
{
  // some variable
}


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

Ответ 7

#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));
}

Ответ 8

Да, вы можете эмулировать свое наследие en C, используя технику "Puncing". Это объявление базового класса (struct) внутри производного класса и литье производного в качестве базы:

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

Но вы должны объявить базовый класс в первой позиции в вашей производной структуре, если вы хотите использовать производную базу в программе:

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

В этом фрагменте вы можете использовать только базовый класс.

Я использую эту технику в своих проектах: oop4c