Wie kann Vererbung mit C modelliert werden? [duplicate]

Lesezeit: 7 Minuten

Benutzeravatar von Agnel Kurian
Agnel Kurian

Ist es möglich, die Vererbung mit C zu modellieren? Wie? Beispielcode hilft.

Bearbeiten: Ich möchte sowohl Daten als auch Methoden erben. Containerschiff allein wird nicht helfen. Ersetzbarkeit – die Verwendung eines beliebigen abgeleiteten Klassenobjekts, bei dem ein Basisklassenobjekt funktioniert – ist das, was ich brauche.

  • Was ist der Grund dafür?

    – Artem Barger

    6. August 2009 um 6:33 Uhr

  • Da frühe Versionen von C++ hauptsächlich ein Präprozessor waren, der in C konvertiert wurde, ist dies durchaus möglich.

    – mhawke

    6. August 2009 um 6:39 Uhr

  • Ich habe etwas C-Code, der hauptsächlich Containerschiffe verwendet. Das Projekt ist an einem Punkt angelangt, an dem Substituierbarkeit (eine „ist ein“-Beziehung) sehr wünschenswert geworden ist.

    – Agnel Kurian

    6. August 2009 um 6:47 Uhr

  • beantwortet im Grunde alle Ihre Fragen: http://stackoverflow.com/questions/415452/object-orientation-in-c/415536#415536

    – Junier

    6. August 2009 um 6:48 Uhr

  • Mit C können Sie (fast) objektorientierten Code schreiben, aber er wäre nicht stark typisiert.

    – Zaxter

    3. September 2015 um 11:46 Uhr

Es ist sehr einfach, so zu gehen:

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

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

struct child derived;

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

Aber wenn Sie die MS-Erweiterung verwenden (in GCC use -fms-extensions Flag) können Sie anonym verschachtelt verwenden structs und es wird viel besser aussehen:

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

struct child derived;

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

  • schön, aber jetzt wird CLang das nicht kompilieren ..

    – makapuf

    19. Februar 2018 um 21:04 Uhr

  • @makapuf C11 unterstützt es als Standardfunktion (de.wikipedia.org/wiki/…), Also clang sollte es mit unterstützen -std=c11

    – qrdl

    20. Februar 2018 um 6:52 Uhr

  • naja, nicht gerade wie es scheint. C11 akzeptiert es mit anonymen Strukturen ohne Tags, sodass Sie eine andere unbenannte Struktur einbetten könnten, aber eine vorherige Strukturdefinition nicht wiederverwenden können … (warum dies der Fall ist, weiß ich nicht).

    – makapuf

    28. Februar 2018 um 22:44 Uhr

  • @makapuf ja kannst du. Ich habe es gerade getestet und Sie können zuvor definierte Strukturen und zuvor typdefinierte Strukturen verwenden. Aber Sie müssen C11 UND das Flag verwenden, überprüfen Sie gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html

    – m4l490n

    30. Oktober 2019 um 16:13 Uhr


Benutzeravatar von Jérémie Koenig
Jérémie König

Sie können C definitiv in einem (etwas) objektorientierten Stil schreiben.

Die Kapselung kann erfolgen, indem Sie die Definitionen Ihrer Strukturen in der .c-Datei und nicht im zugehörigen Header behalten. Dann handhabt die Außenwelt Ihre Objekte, indem sie Zeiger auf sie hält, und Sie stellen Funktionen bereit, die solche Zeiger als die “Methoden” Ihrer Objekte akzeptieren.

Polymorphismus-ähnliches Verhalten kann durch Verwendung von Funktionszeigern erreicht werden, die normalerweise in “Operationsstrukturen” gruppiert sind, ähnlich wie die “virtuelle Methodentabelle” in Ihren C++-Objekten (oder wie auch immer sie genannt wird). Die ops-Struktur kann auch andere Dinge wie Konstanten enthalten, deren Wert spezifisch für eine bestimmte “Unterklasse” ist. Die “Eltern”-Struktur kann einen Verweis auf ops-spezifische Daten durch eine generische void* Zeiger. Natürlich könnte die “Unterklasse” das Muster für mehrere Vererbungsebenen wiederholen.

Also, im Beispiel unten, struct printer ähnelt einer abstrakten Klasse, die durch Ausfüllen von a “abgeleitet” werden kann pr_ops -Struktur und Bereitstellen einer Konstruktorfunktionsumhüllung pr_create(). Jeder Untertyp wird seine eigene Struktur haben, die in der “verankert” wird struct printer Objekt durch die data generischer Zeiger. Dies belegen die fileprinter Untertyp. Man könnte sich einen GUI- oder Socket-basierten Drucker vorstellen, der unabhängig vom restlichen Code so manipuliert würde struct printer * Hinweis.

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

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

Schließlich 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. Auch als historische Anmerkung – die ersten C++-Compiler gaben keinen Maschinencode, sondern C-Code aus, weil er schneller und einfacher zu implementieren war (die C-to-Machine-Code-Schicht existierte). Also, es kann definitiv in C gemacht werden.

    – TomTom

    19. Dezember 2010 um 21:01 Uhr

Ja, Sie können Heritance en C emulieren, indem Sie die Technik des “Typenspiels” verwenden. Das ist die Deklaration der Basisklasse (struct) innerhalb der abgeleiteten Klasse und die Umwandlung der abgeleiteten Klasse in eine Basis:

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

Aber Sie müssen die Basisklasse an der ersten Position in Ihrer abgeleiteten Struktur deklarieren, wenn Sie die abgeleitete Klasse als Basis in ein Programm umwandeln möchten:

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

In diesem Snippet können Sie nur die Basisklasse verwenden.

Ich verwende diese Technik in meinen Projekten: oop4c

  • Sollten es nicht &d und &d2 sein?

    – Ajay Brahmakshatriya

    4. April 2017 um 18:43 Uhr

Benutzeravatar von rslite
rslite

Es sollte zumindest teilweise möglich sein.

Was genau brauchen Sie zum Modellieren? Die Vererbung der Daten oder der Methoden?

Bearbeiten: Hier ist ein kurzer Artikel, den ich gefunden habe: http://fluff.info/blog/arch/00000162.htm

Ich habe ein Objektsystem in C verwendet, das spät gebundene Methoden verwendete, die eine Objektorientierung mit Reflektion ermöglichten.

Sie können darüber lesen hier.

  • in der Tat; Das Thema ist viel zu breit, um es in einer einzigen Antwort auf Stackoverflow vollständig abzudecken. Auf den ersten Blick denke ich, dass der verlinkte Artikel ein gutes Geschäft abdeckt. Ich mag die Erklärung von Miro Samek in “Practical Statecharts in C/C++” (nur 1. Auflage)

    – Adrian

    6. August 2009 um 7:02 Uhr

Benutzeravatar von Exikle
Exikle

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

  • in der Tat; Das Thema ist viel zu breit, um es in einer einzigen Antwort auf Stackoverflow vollständig abzudecken. Auf den ersten Blick denke ich, dass der verlinkte Artikel ein gutes Geschäft abdeckt. Ich mag die Erklärung von Miro Samek in “Practical Statecharts in C/C++” (nur 1. Auflage)

    – Adrian

    6. August 2009 um 7:02 Uhr

malays Benutzeravatar
malaiisch

Dieser Link könnte nützlich sein -> Verknüpfung

Das grundlegende Beispiel wird wie folgt aussehen

 struct BaseStruct
{
  // some variable
}


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

1411790cookie-checkWie kann Vererbung mit C modelliert werden? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy