Polymorphismus (in C) [duplicate]

Lesezeit: 4 Minuten

Benutzer-Avatar
Belgien

Mögliches Duplikat:

Wie kann ich Polymorphismus im OO-Stil in C simulieren?

Ich versuche, die Idee des Polymorphismus mit Beispielen aus Sprachen, die ich kenne, besser zu verstehen. Gibt es Polymorphismus in C?

  • Sie können immer etwas Polymorphes schreiben, indem Sie beispielsweise eine vtable-Technologie implementieren. Es geht nur darum, mit Funktionszeigern herumzuspielen, um eine geeignete Indirektionsebene zu erstellen.

    – Kerrek SB

    19. November 2011 um 13:11 Uhr


  • stackoverflow.com/questions/524033/…

    – 0x90

    19. November 2011 um 13:22 Uhr


Benutzer-Avatar
Christoph

Dies ist Nekuromentos zweites Beispiel, das so berücksichtigt wird, wie ich es für objektorientiertes C als idiomatisch betrachte:

tier.h

#ifndef ANIMAL_H_
#define ANIMAL_H_

struct animal
{
    // make vtable_ a pointer so they can be shared between instances
    // use _ to mark private members
    const struct animal_vtable_ *vtable_;
    const char *name;
};

struct animal_vtable_
{
    const char *(*sound)(void);
};

// wrapper function
static inline const char *animal_sound(struct animal *animal)
{
    return animal->vtable_->sound();
}

// make the vtables arrays so they can be used as pointers
extern const struct animal_vtable_ CAT[], DOG[];

#endif

Kat.c

#include "animal.h"

static const char *sound(void)
{
    return "meow!";
}

const struct animal_vtable_ CAT[] = { { sound } };

Hund.c

#include "animal.h"

static const char *sound(void)
{
    return "arf!";
}

const struct animal_vtable_ DOG[] = { { sound } };

Haupt c

#include "animal.h"
#include <stdio.h>

int main(void)
{
    struct animal kitty = { CAT, "Kitty" };
    struct animal lassie = { DOG, "Lassie" };

    printf("%s says %s\n", kitty.name, animal_sound(&kitty));
    printf("%s says %s\n", lassie.name, animal_sound(&lassie));

    return 0;
}

Dies ist ein Beispiel für Laufzeitpolymorphismus, da zu diesem Zeitpunkt die Methodenauflösung erfolgt.

C1x fügte generische Auswahlen hinzu, die Polymorphismus zur Kompilierzeit über Makros ermöglichen. Das folgende Beispiel stammt aus dem C1x-April-Entwurf, Abschnitt 6.5.1.1 §5:

#define cbrt(X) _Generic((X), \
    long double: cbrtl, \
    default: cbrt, \
    float: cbrtf \
)(X)

Typgenerische Makros für mathematische Funktionen waren bereits in C99 über den Header verfügbar tgmath.haber es gab keine Möglichkeit für Benutzer, ihre eigenen Makros zu definieren, ohne Compiler-Erweiterungen zu verwenden.

  • Ist es Konvention zu setzen DOG UND CAT in animal.h? Ich könnte mir vorstellen, dass sie auch in ihre jeweilige Kopfzeile gehen können.

    – Brady Dean

    12. Februar 2019 um 22:21 Uhr

Fast alle Implementierungen des Laufzeitpolymorphismus in C verwenden Funktionszeiger, also ist dies der Grundbaustein.

Hier ist ein einfaches Beispiel, wenn sich das Laufzeitverhalten einer Prozedur abhängig von ihrem Argument ändert.

#include <stdio.h>

int tripple(int a) {
    return 3 * a;
}

int square(int a) {
    return a * a;
}

void transform(int array[], size_t len, int (*fun)(int)) {
    size_t i = 0;
    for(; i < len; ++i)
        array[i] = fun(array[i]);
}

int main() {
    int array[3] = {1, 2, 3};
    transform(array, 3, &tripple);
    transform(array, 3, &square);

    size_t i = 0;
    for (; i < 3; ++i)
        printf("%d ", array[i]);

    return 0;
}

Mit Funktionszeigern können Sie erstellen Virtuelle Tische und verwenden Sie es, um “Objekte” zu erstellen, die einheitlich behandelt werden, sich aber zur Laufzeit unterschiedlich verhalten.

#include <stdio.h>

struct animal_vtable {
    const char* (*sound)();
};

struct animal {
    struct animal_vtable methods;
    const char* name;
};

const char* cat_sound() {
    return "meow!";
}

const char* dog_sound() {
    return "bark!";
}

void describe(struct animal *a) {
    printf("%s makes \"%s\" sound.\n", a->name, a->methods.sound());
}

struct animal cat = {{&cat_sound}, "cat"};
struct animal dog = {{&dog_sound}, "dog"};

int main() {
    describe(&cat);
    describe(&dog);

    return 0;
}

  • die ‘idiomatische’ Art, OO in C zu machen (sofern es so etwas gibt), würde das machen methods Mitglied von struct animal ein Zeiger, damit verschiedene Instanzen derselben ‘Klasse’ ihre vtables teilen können

    – Christoph

    19. November 2011 um 13:59 Uhr

  • @Christoph: Das ist eine zusätzliche Ebene der Indirektion, kann eine gute oder schlechte Sache sein. Es ist ein Kompromiss zwischen Platz und Geschwindigkeit.

    – Karoly Horvath

    19. November 2011 um 14:29 Uhr

  • @yi_H: sicher, aber ich würde trotzdem in Betracht ziehen, Zeiger idiomatisch zu verwenden, da die vtable der Klasse eines Objekts entspricht, die (zumindest konzeptionell) von Instanzen gemeinsam genutzt wird. Wenn Sie es so betrachten, bietet das Einbinden der vtable in die Instanz einen Methoden-Cache, dh es ist eine Form der Optimierung …

    – Christoph

    19. November 2011 um 14:42 Uhr


  • @Christoph: Das liegt daran, dass du mitdenkst Klassen. Stellen Sie sich ein System vor, bei dem jeder vtable-Eintrag unabhängig gesetzt werden kann. dort würde ein Klassenansatz zu einer kombinatorischen Explosion führen. Noch einmal, ich sage nur, es gibt kein Rechts Ansatz, gibt es Kompromisse.

    – Karoly Horvath

    19. November 2011 um 16:05 Uhr


  • “Woof” ist das idiomatische Geräusch, das von Dog ausgestrahlt wird, wie in RFC K9 festgelegt

    – Matt Montag

    28. Mai 2019 um 2:16 Uhr

Es gibt keine intrinsische Unterstützung für Polymorphismus in C, aber es gibt Entwurfsmuster, die Funktionszeiger, Umwandlungen von Basisklassen (Strukturen) usw. verwenden, die ein logisches Äquivalent zum dynamischen Dispatch bieten können. Das GTK-Bibliothek ist gutes Beispiel.

Ich denke, Sie haben bereits den Wikipedia-Artikel überprüft Polymorphismus.

In der Informatik ist Polymorphismus ein Merkmal einer Programmiersprache, das es ermöglicht, Werte unterschiedlicher Datentypen über eine einheitliche Oberfläche zu behandeln.

Gemäß dieser Definition unterstützt C nativ keinen Polymorphismus. Beispielsweise gibt es keine allgemeine Funktion zum Ermitteln des Absolutwerts einer Zahl (abs und fabs sind für ganze Zahlen bzw. Doubles).

Wenn Sie auch mit C++ vertraut sind, werfen Sie einen Blick auf OOP-Vererbung und Vorlagen – das sind dort Mechanismen für Polymorphie.

1344060cookie-checkPolymorphismus (in C) [duplicate]

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

Privacy policy