Wie würde man objektorientierten Code in C schreiben? [closed]

Lesezeit: 7 Minuten

Welche Möglichkeiten gibt es, objektorientierten Code in C zu schreiben? Vor allem im Hinblick auf Polymorphie.


Siehe auch diese Stack Overflow-Frage Objektorientierung in C.

  • ldeniau.web.cern.ch/ldeniau/html/oopc.html”>Objekt Orientierte Programmierung in C von Laurent Deniau

    John

    31. März 2009 um 17:42 Uhr

  • @Camilo Martin: Ich habe absichtlich gefragt kann nicht sollte. Ich bin eigentlich nicht daran interessiert, OOP in C zu verwenden. Wenn ich jedoch OO-Lösungen in C sehe, lerne ich/wir mehr über die Grenzen und/oder Flexibilität von C und auch über kreative Wege zur Implementierung und Verwendung von Polymorphismus.

    – Dina

    24. November 2010 um 16:17 Uhr

  • OO ist nur ein Muster. Überprüfen Sie hier, es kann sogar in gemacht werden .bat-Dateien: dirk.rave.org/chap9.txt (Jedes Muster kann auf jede Programmiersprache angewendet werden, wenn Sie interessiert genug sind, denke ich). Das ist aber ein guter Denkanstoß. Und wahrscheinlich kann man viel lernen, wenn man solche Muster, die wir für selbstverständlich halten, auf Sprachen anwendet, die sie nicht haben.

    – Camilo Martin

    24. November 2010 um 19:47 Uhr


  • GTK – entschuldigen Sie, GObject – ist eigentlich ein ziemlich gutes Beispiel für OOP (sorta) in C. Also, um @Camilo zu antworten, für C-Interpoliabilität.

    – neu123456

    14. Dezember 2010 um 22:59 Uhr


  • Es ist wirklich schockierend, wie diese Frage hätte geschlossen werden können. Es ist eine sehr gute Frage, ein Augenöffner, wie die erhaltenen Punkte zeigen. Es sagt nur, wie SO angetrieben wird …

    – zess

    12. April 2020 um 19:07 Uhr

Da Sie über Polymorphismus sprechen, ja, das können Sie, wir haben diese Art von Sachen gemacht, Jahre bevor C++ aufkam.

Grundsätzlich verwendet man a struct um sowohl die Daten als auch eine Liste von Funktionszeigern zu halten, die auf die relevanten Funktionen für diese Daten zeigen.

In einer Kommunikationsklasse hätten Sie also einen Open-, Read-, Write- und Close-Aufruf, der als vier Funktionszeiger in der Struktur neben den Daten für ein Objekt verwaltet würde, etwa so:

typedef struct {
    int (*open)(void *self, char *fspec);
    int (*close)(void *self);
    int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    // And data goes here.
} tCommClass;

tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;

tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;

Natürlich wären diese obigen Codesegmente tatsächlich in einem “Konstruktor” wie z rs232Init().

Wenn Sie von dieser Klasse „erben“, ändern Sie einfach die Zeiger so, dass sie auf Ihre eigenen Funktionen zeigen. Jeder, der diese Funktionen aufgerufen hat, würde dies über die Funktionszeiger tun und Ihnen Ihren Polymorphismus geben:

int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");

Art wie eine manuelle vtable.

Sie könnten sogar virtuelle Klassen haben, indem Sie die Zeiger auf NULL setzen – das Verhalten würde sich geringfügig von C++ unterscheiden (ein Core-Dump zur Laufzeit statt eines Fehlers zur Kompilierzeit).

Hier ist ein Beispielcode, der dies demonstriert. Zuerst die Klassenstruktur der obersten Ebene:

#include <stdio.h>

// The top-level class.

typedef struct sCommClass {
    int (*open)(struct sCommClass *self, char *fspec);
} tCommClass;

Dann haben wir die Funktionen für die TCP-‘Unterklasse’:

// Function for the TCP 'class'.

static int tcpOpen (tCommClass *tcp, char *fspec) {
    printf ("Opening TCP: %s\n", fspec);
    return 0;
}
static int tcpInit (tCommClass *tcp) {
    tcp->open = &tcpOpen;
    return 0;
}

Und das HTTP auch:

// Function for the HTTP 'class'.

static int httpOpen (tCommClass *http, char *fspec) {
    printf ("Opening HTTP: %s\n", fspec);
    return 0;
}
static int httpInit (tCommClass *http) {
    http->open = &httpOpen;
    return 0;
}

Und schließlich ein Testprogramm, um es in Aktion zu zeigen:

// Test program.

int main (void) {
    int status;
    tCommClass commTcp, commHttp;

    // Same 'base' class but initialised to different sub-classes.

    tcpInit (&commTcp);
    httpInit (&commHttp);

    // Called in exactly the same manner.

    status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
    status = (commHttp.open)(&commHttp, "http://www.microsoft.com");

    return 0;
}

Dies erzeugt die Ausgabe:

Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com

So können Sie sehen, dass je nach Unterklasse unterschiedliche Funktionen aufgerufen werden.

  • Kapselung ist ziemlich einfach, Polymorphismus ist machbar – aber Vererbung ist schwierig

    – Martin Beckett

    19. Juli 2010 um 16:10 Uhr

  • lwn.net veröffentlichte kürzlich einen Artikel mit dem Titel Objektorientiertes Design Muster im Kernel zum Thema Strukturen ähnlich der obigen Antwort – das heißt, eine Struktur, die Funktionszeiger enthält, oder ein Zeiger auf eine Struktur, die Funktionen hat, die einen Zeiger auf die Struktur mit den Daten, mit denen wir arbeiten, als Parameter nehmen.

    Benutzer107498

    5. Juni 2011 um 0:51 Uhr


  • +1 Schönes Beispiel! Obwohl, wenn jemand wirklich diesen Weg gehen möchte, es für “Instanz”-Strukturen angemessener wäre, a zu haben einzelnes Feld auf ihre Instanz “virtuelle Tabelle” zeigen, die alle virtuellen Funktionen für diesen Typ an einem Ort enthält. Dh deine tCommClass umbenannt würde in tCommVTund ein tCommClass struct hätte nur Datenfelder und ein einzelnes tCommVT vt Feld, das auf den “einzigen” virtuellen Tisch zeigt. Das Herumtragen aller Zeiger mit jeder Instanz fügt unnötigen Overhead hinzu und ähnelt meiner Meinung nach eher der Vorgehensweise in JavaScript als C++.

    – Groo

    23. Oktober 2013 um 7:45 Uhr


  • Dies demonstriert also die Implementierung einer einzelnen Schnittstelle, aber was ist mit der Implementierung mehrerer Schnittstellen? Oder Mehrfachvererbung?

    – weberc2

    7. Juli 2014 um 15:35 Uhr

  • Weber, wenn Sie alle Funktionen von C++ nutzen möchten, sollten Sie wahrscheinlich C++ verwenden. Die Frage wurde speziell nach Polymorphismus gestellt, der Fähigkeit von Objekten, eine andere “Form” anzunehmen. Sie können sicherlich Schnittstellen und Mehrfachvererbung in C durchführen, aber es ist ein ziemlicher Mehraufwand, und Sie müssen die Smarts selbst verwalten, anstatt die in C++ integrierten Dinge zu verwenden.

    – paxdiablo

    7. Juli 2014 um 22:05 Uhr

  • @nategoose – st->my_type->push(st, thing2); Anstatt von st->my_type.push(st, thing2);

    – Fabricio

    3. Juni 2012 um 12:48 Uhr

  • @nategoose: ODER struct stack_type my_type; Anstatt von struct stack_type * my_type;

    – Fabricio

    3. Juni 2012 um 16:18 Uhr

  • Ich mag das Konzept, eine Struktur für die Klasse zu haben. Aber wie wäre es mit einem Generikum Class struktur? Das würde das OO C machen mehr dynamischer als C++. Wie wär es damit? Übrigens +1.

    – Linuxios

    28. Juli 2012 um 20:21 Uhr

Ich glaube, dass die Implementierung von OOP in C nicht nur an sich nützlich ist, sondern auch eine hervorragende Möglichkeit, dies zu tun lernen OOP und sein Innenleben verstehen. Die Erfahrung vieler Programmierer hat gezeigt, dass ein Programmierer verstehen muss, wie die zugrunde liegenden Konzepte letztendlich implementiert werden, um eine Technik effizient und sicher einzusetzen. Das Emulieren von Klassen, Vererbung und Polymorphismus in C lehrt genau das.

Um die ursprüngliche Frage zu beantworten, hier sind ein paar Ressourcen, die zeigen, wie man OOP in C macht:

Der EmbeddedGurus.com-Blogbeitrag „Objektbasierte Programmierung in C“ zeigt, wie Klassen und Einzelvererbung in portablem C implementiert werden:
http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c/

Application Note „„C+“—Object Oriented Programming in C“ zeigt die Implementierung von Klassen, Einfachvererbung und später Bindung (Polymorphismus) in C mithilfe von Präprozessor-Makros:
http://www.state-machine.com/resources/cplus_3.0_manual.pdfder Beispielcode ist unter verfügbar http://www.state-machine.com/resources/cplus_3.0.zip

Ich habe es fertig gesehen. Ich würde es nicht empfehlen. C++ begann auf diese Weise ursprünglich als Präprozessor, der als Zwischenschritt C-Code produzierte.

Im Wesentlichen erstellen Sie eine Dispatch-Tabelle für alle Ihre Methoden, in der Sie Ihre Funktionsreferenzen speichern. Das Ableiten einer Klasse würde das Kopieren dieser Dispatch-Tabelle und das Ersetzen der Einträge, die Sie überschreiben wollten, mit sich bringen, wobei Ihre neuen “Methoden” die ursprüngliche Methode aufrufen müssten, wenn sie die Basismethode aufrufen möchten. Am Ende schreiben Sie C++ neu.

Sicher ist das möglich. Das ist was GObjectder Rahmen, der alle GTK+ und Gnom basiert auf, tut.

  • Was sind Vor-/Nachteile eines solchen Ansatzes? Dh. Es ist viel einfacher, es mit C++ zu schreiben.

    – kravemir

    6. Februar 2018 um 7:42 Uhr

  • @kravemir Nun, C++ ist nicht ganz so portabel wie C, und es ist etwas schwieriger, C++ mit Code zu verknüpfen, der möglicherweise von einem anderen C++-Compiler kompiliert wird. Aber ja, es ist einfacher, Klassen in C++ zu schreiben, obwohl GObject auch nicht wirklich so schwierig ist (vorausgesetzt, Sie haben nichts gegen eine kleine Textbausteine).

    – Edwin Buck

    18. April 2018 um 4:46 Uhr

1428100cookie-checkWie würde man objektorientierten Code in C schreiben? [closed]

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

Privacy policy