Wie kann man objektorientierten Code in C schreiben? Besonders im Hinblick auf Polymorphismus.
Siehe auch diese Stack - Überlauf Frage Objektorientierung in C .
Wie kann man objektorientierten Code in C schreiben? Besonders im Hinblick auf Polymorphismus.
Siehe auch diese Stack - Überlauf Frage Objektorientierung in C .
Antworten:
Ja. Tatsächlich stellt Axel Schreiner sein Buch "Objektorientierte Programmierung in ANSI-C" kostenlos zur Verfügung, das das Thema ziemlich ausführlich behandelt.
quelle
Da Sie dann über Polymorphismus sprechen, haben wir solche Dinge Jahre vor C ++ gemacht.
Grundsätzlich verwenden Sie a
struct
, um sowohl die Daten als auch eine Liste von Funktionszeigern zu speichern, um auf die relevanten Funktionen für diese Daten zu verweisen.In einer Kommunikationsklasse hätten Sie also einen Aufruf zum Öffnen, Lesen, Schreiben und Schließen, der als vier Funktionszeiger in der Struktur neben den Daten für ein Objekt beibehalten wird, etwa:
Natürlich würden sich diese obigen Codesegmente tatsächlich in einem "Konstruktor" wie z
rs232Init()
.Wenn Sie von dieser Klasse 'erben', ändern Sie einfach die Zeiger, um auf Ihre eigenen Funktionen zu verweisen. Jeder, der diese Funktionen aufgerufen hat, würde dies über die Funktionszeiger tun und Ihnen Ihren Polymorphismus geben:
So ähnlich wie eine manuelle Tabelle.
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 anstelle eines Fehlers zur Kompilierungszeit).
Hier ist ein Beispielcode, der dies demonstriert. Zuerst die Klassenstruktur der obersten Ebene:
Dann haben wir die Funktionen für die TCP-Unterklasse:
Und das HTTP auch:
Und zum Schluss ein Testprogramm, um es in Aktion zu zeigen:
Dies erzeugt die Ausgabe:
So können Sie sehen, dass die verschiedenen Funktionen abhängig von der Unterklasse aufgerufen werden.
quelle
tCommClass
würden in umbenannttCommVT
, und einetCommClass
Struktur hätte nur Datenfelder und ein einzelnestCommVT vt
Feld, das auf die "einzige" virtuelle Tabelle verweist. Das Mitführen aller Zeiger mit jeder Instanz erhöht den unnötigen Overhead und ähnelt eher der Vorgehensweise in JavaScript als in C ++, IMHO.Namespaces werden häufig folgendermaßen erstellt:
anstatt
Um eine C- Struktur in eine C ++ - Klasse zu verwandeln, können Sie Folgendes tun:
In
Und TU:
Ich habe den Destruktor nicht ausgeführt oder gelöscht, aber er folgt demselben Muster.
this_is_here_as_an_example_only ist wie eine statische Klassenvariable, die von allen Instanzen eines Typs gemeinsam genutzt wird. Alle Methoden sind wirklich statisch, außer dass einige dies * annehmen
quelle
st->my_type->push(st, thing2);
anstelle vonst->my_type.push(st, thing2);
struct stack_type my_type;
stattstruct stack_type * my_type;
Class
Struktur? Das wäre der OO C macht mehr dynamischer als C ++. Wie ist es damit? Übrigens +1.Ich glaube, dass die Implementierung von OOP in C nicht nur für sich genommen nützlich ist, sondern auch eine hervorragende Möglichkeit ist , OOP zu lernen und sein Innenleben zu 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 dies.
Um die ursprüngliche Frage zu beantworten, finden Sie hier einige Ressourcen, die zeigen, wie OOP in C ausgeführt wird:
Der Blog-Beitrag von EmbeddedGurus.com "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 /.
Anwendungshinweis "" C + "- Objektorientierte Programmierung in C" zeigt, wie Klassen, Einzelvererbung und späte Bindung (Polymorphismus) in C mithilfe von Präprozessor-Makros implementiert werden: http://www.state-machine.com/resources/cplus_3. 0_manual.pdf , der Beispielcode ist unter http://www.state-machine.com/resources/cplus_3.0.zip verfügbar
quelle
Ich habe es gesehen. Ich würde es nicht empfehlen. C ++ begann ursprünglich auf diese Weise als Präprozessor, der C-Code als Zwischenschritt erzeugte.
Im Wesentlichen erstellen Sie am Ende eine Versandtabelle für alle Ihre Methoden, in der Sie Ihre Funktionsreferenzen speichern. Das Ableiten einer Klasse würde das Kopieren dieser Versandtabelle und das Ersetzen der Einträge erfordern, die Sie überschreiben möchten, wobei Ihre neuen "Methoden" die ursprüngliche Methode aufrufen müssen, wenn sie die Basismethode aufrufen möchten. Schließlich schreiben Sie C ++ neu.
quelle
glib
objektiv in C geschrieben?Sicher ist das möglich. Dies ist, was GObject , das Framework, auf dem alle GTK + und GNOME basieren, tut.
quelle
Die C stdio FILE-Unterbibliothek ist ein hervorragendes Beispiel für die Erstellung von Abstraktion, Kapselung und Modularität in unverfälschtem C.
Vererbung und Polymorphismus - die anderen Aspekte, die häufig als wesentlich für OOP angesehen werden - liefern nicht unbedingt die versprochenen Produktivitätsgewinne, und es wurden vernünftige Argumente dafür vorgebracht, dass sie die Entwicklung und das Nachdenken über den Problembereich tatsächlich behindern können.
quelle
Triviales Beispiel mit einem Tier und einem Hund: Sie spiegeln den vtable-Mechanismus von C ++ wider (größtenteils sowieso). Sie trennen auch Zuordnung und Instanziierung (Animal_Alloc, Animal_New), damit wir malloc () nicht mehrmals aufrufen. Wir müssen den
this
Zeiger auch explizit weitergeben .Wenn Sie nicht virtuelle Funktionen ausführen, ist das ein Trival. Sie fügen sie einfach nicht zur vtable hinzu und für statische Funktionen ist kein
this
Zeiger erforderlich . Für die Mehrfachvererbung sind im Allgemeinen mehrere vtables erforderlich, um Mehrdeutigkeiten aufzulösen.Außerdem sollten Sie in der Lage sein, setjmp / longjmp für die Ausnahmebehandlung zu verwenden.
PS. Dies wird auf einem C ++ - Compiler getestet, es sollte jedoch einfach sein, es auf einem C-Compiler zum Laufen zu bringen.
quelle
typedef
innerhalb von astruct
ist in C. nicht möglichSchauen Sie sich GObject an . Es soll OO in C sein und eine Implementierung dessen, wonach Sie suchen. Wenn Sie jedoch wirklich OO möchten, wählen Sie C ++ oder eine andere OOP-Sprache. Es kann manchmal sehr schwierig sein, mit GObject zu arbeiten, wenn Sie es gewohnt sind, mit OO-Sprachen umzugehen, aber wie alles andere werden Sie sich an die Konventionen und den Ablauf gewöhnen.
quelle
Das war interessant zu lesen. Ich habe selbst über dieselbe Frage nachgedacht, und die Vorteile des Nachdenkens sind folgende:
Der Versuch, mir vorzustellen, wie OOP-Konzepte in einer Nicht-OOP-Sprache implementiert werden, hilft mir, die Stärken der OOp-Sprache (in meinem Fall C ++) zu verstehen. Dies hilft mir, besser zu beurteilen, ob ich C oder C ++ für einen bestimmten Anwendungstyp verwenden soll - wobei die Vorteile des einen den anderen überwiegen.
Beim Surfen im Internet nach Informationen und Meinungen dazu fand ich einen Autor, der Code für einen eingebetteten Prozessor schrieb und nur einen C-Compiler zur Verfügung hatte: http://www.eetimes.com/discussion/other/4024626/Object-Oriented -C-Erstellen-Foundation-Klassen-Teil-1
In seinem Fall war die Analyse und Anpassung von OOP-Konzepten in Ebene C eine gültige Aufgabe. Es scheint, dass er offen dafür war, einige OOP-Konzepte zu opfern, da der Leistungsaufwand durch den Versuch, sie in C zu implementieren, beeinträchtigt wurde.
Die Lektion, die ich genommen habe, ist: Ja, es kann bis zu einem gewissen Grad getan werden, und ja, es gibt einige gute Gründe, es zu versuchen.
Am Ende dreht die Maschine Stapelzeigerbits, wodurch der Programmzähler herumspringt und Speicherzugriffsoperationen berechnet werden. Unter dem Gesichtspunkt der Effizienz ist es umso besser, je weniger Berechnungen von Ihrem Programm durchgeführt werden. Manchmal müssen wir diese Steuer jedoch einfach zahlen, damit wir unser Programm so organisieren können, dass es am wenigsten anfällig für menschliches Versagen ist. Der OOP-Sprachcompiler ist bestrebt, beide Aspekte zu optimieren. Der Programmierer muss diese Konzepte in einer Sprache wie C viel sorgfältiger umsetzen.
quelle
Es kann hilfreich sein, die Dokumentation von Apple zu den Core Foundation-APIs zu lesen. Es ist eine reine C-API, aber viele der Typen sind mit Objective-C-Objektäquivalenten verbunden.
Es kann auch hilfreich sein, sich das Design von Objective-C selbst anzusehen. Es unterscheidet sich ein wenig von C ++ darin, dass das Objektsystem in Bezug auf C-Funktionen definiert ist, z. B.
objc_msg_send
um eine Methode für ein Objekt aufzurufen. Der Compiler übersetzt die Syntax in eckigen Klammern in diese Funktionsaufrufe, sodass Sie sie nicht kennen müssen. Wenn Sie jedoch Ihre Frage berücksichtigen, ist es möglicherweise hilfreich, zu erfahren, wie sie unter der Haube funktioniert.quelle
Es gibt verschiedene Techniken, die verwendet werden können. Das wichtigste ist mehr, wie man das Projekt aufteilt. Wir verwenden in unserem Projekt eine Schnittstelle, die in einer .h-Datei deklariert ist, und die Implementierung des Objekts in einer .c-Datei. Der wichtige Teil ist, dass alle Module, die die .h-Datei enthalten, nur ein Objekt als sehen
void *
, und die .c-Datei das einzige Modul ist, das die Interna der Struktur kennt.So etwas für eine Klasse nennen wir FOO als Beispiel:
In der .h-Datei
Die C-Implementierungsdatei wird ungefähr so sein.
Daher gebe ich den Zeiger explizit auf ein Objekt für jede Funktion dieses Moduls. Ein C ++ - Compiler macht das implizit und in C schreiben wir es explizit aus.
Ich verwende es wirklich
this
in meinen Programmen, um sicherzustellen, dass mein Programm nicht in C ++ kompiliert wird, und es hat die feine Eigenschaft, in meinem Syntaxhervorhebungseditor in einer anderen Farbe zu sein.Die Felder des FOO_struct können in einem Modul geändert werden, und ein anderes Modul muss nicht einmal neu kompiliert werden, um weiterhin verwendet werden zu können.
Mit diesem Stil beschäftige ich mich bereits mit einem großen Teil der Vorteile von OOP (Datenkapselung). Durch die Verwendung von Funktionszeigern ist es sogar einfach, so etwas wie Vererbung zu implementieren, aber ehrlich gesagt ist es wirklich nur selten nützlich.
quelle
typedef struct FOO_type FOO_type
anstelle eines typedef den Header ungültig machen, erhalten Sie den zusätzlichen Vorteil der Typprüfung, ohne Ihre Struktur verfügbar zu machen.Sie können es mit Funktionszeigern fälschen, und tatsächlich denke ich, dass es theoretisch möglich ist, C ++ - Programme in C zu kompilieren.
Es ist jedoch selten sinnvoll, einer Sprache ein Paradigma aufzuzwingen, anstatt eine Sprache auszuwählen, die ein Paradigma verwendet.
quelle
Objektorientiertes C, kann gemacht werden, ich habe diese Art von Code in der Produktion in Korea gesehen, und es war das schrecklichste Monster, das ich seit Jahren gesehen habe (dies war wie letztes Jahr (2007), als ich den Code gesehen habe). Also ja, es kann getan werden, und ja, die Leute haben es schon einmal getan und tun es auch heute noch. Aber ich würde C ++ oder Objective-C empfehlen, beide sind aus C geborene Sprachen, um der Objektorientierung unterschiedliche Paradigmen zu bieten.
quelle
Wenn Sie davon überzeugt sind, dass ein OOP-Ansatz für das Problem, das Sie lösen möchten, überlegen ist, warum sollten Sie versuchen, ihn mit einer Nicht-OOP-Sprache zu lösen? Anscheinend verwenden Sie das falsche Tool für den Job. Verwenden Sie C ++ oder eine andere objektorientierte C-Variantensprache.
Wenn Sie fragen, weil Sie mit dem Codieren eines bereits vorhandenen großen Projekts in C beginnen, sollten Sie nicht versuchen, Ihre eigenen (oder die anderer) OOP-Paradigmen in die Infrastruktur des Projekts zu zwingen. Befolgen Sie die Richtlinien, die bereits im Projekt vorhanden sind. Im Allgemeinen sauber APIs und isoliert Bibliotheken und Module werden einen langen Weg in Richtung mit einem sauberen OOP- gehen ish Designs.
Wenn Sie nach all dem wirklich auf OOP C eingestellt sind, lesen Sie dies (PDF).
quelle
Ja, du kannst. Die Leute schrieben objektorientiertes C, bevor C ++ oder Objective-C auf den Markt kamen. Sowohl C ++ als auch Objective-C waren teilweise Versuche, einige der in C verwendeten OO-Konzepte als Teil der Sprache zu formalisieren.
Hier ist ein wirklich einfaches Programm, das zeigt, wie Sie etwas erstellen können, das aussieht / ein Methodenaufruf ist (es gibt bessere Möglichkeiten, dies zu tun. Dies ist nur ein Beweis dafür, dass die Sprache die Konzepte unterstützt):
quelle
Natürlich ist es nicht so hübsch wie die Verwendung einer Sprache mit integrierter Unterstützung. Ich habe sogar "objektorientierten Assembler" geschrieben.
quelle
Ein kleiner OOC-Code zum Hinzufügen:
quelle
Ich grabe das seit einem Jahr:
Da das GObject-System mit reinem C schwer zu verwenden ist, habe ich versucht, einige nette Makros zu schreiben, um den OO-Stil mit C zu vereinfachen.
Hier ist meine Projektseite (ich habe nicht genug Zeit, um en. Doc zu schreiben, aber das Dokument auf Chinesisch ist viel besser).
OOC-GCC
quelle
Es ist ein Beispiel für Vererbung C in Jim Larson 1996 Vortrag bei den gegebenen 312 Programmierung Abschnitt Mittags Seminars hier: High und Low-Level - C .
quelle
Dave Hansons C-Schnittstellen und -Implementierungen eignen sich hervorragend für die Kapselung und Benennung sowie für die Verwendung von Funktionszeigern. Dave versucht nicht, die Vererbung zu simulieren.
quelle
OOP ist nur ein Paradigma, bei dem Daten in Programmen wichtiger als Code sind. OOP ist keine Sprache. So wie einfaches C eine einfache Sprache ist, ist auch OOP in einfachem C einfach.
quelle
Möglicherweise möchten Sie sich mit der Implementierung des Xt- Toolkits für X Window befassen . Sicher, es wird lang im Zahn, aber viele der verwendeten Strukturen wurden so entworfen, dass sie im traditionellen C auf OO-Weise funktionieren. Im Allgemeinen bedeutet dies, hier und da eine zusätzliche Indirektionsebene hinzuzufügen und Strukturen zu entwerfen, die übereinander liegen.
Auf diese Weise können Sie wirklich viel in der Art von OO tun, die sich in C befindet, obwohl es sich manchmal so anfühlt, sind OO-Konzepte nicht vollständig aus dem Geist von entstanden
#include<favorite_OO_Guru.h>
. Sie waren wirklich viele der etablierten Best Practices der Zeit. OO Sprachen und Systeme destillierten und verstärkten nur Teile des Programmierzeitgeists des Tages.quelle
Die Antwort auf die Frage lautet "Ja, Sie können".
Das objektorientierte C (OOC) -Kit ist für diejenigen gedacht, die objektorientiert programmieren möchten, aber auch am guten alten C festhalten. OOC implementiert Klassen, Einzel- und Mehrfachvererbung sowie Ausnahmebehandlung.
Eigenschaften
• Verwendet nur C-Makros und -Funktionen, keine Spracherweiterungen erforderlich! (ANSI-C)
• Einfach zu lesender Quellcode für Ihre Anwendung. Es wurde darauf geachtet, die Dinge so einfach wie möglich zu gestalten.
• Einzelvererbung von Klassen
• Mehrfachvererbung durch Schnittstellen und Mixins (seit Version 1.3)
• Implementieren von Ausnahmen (in reinem C!)
• Virtuelle Funktionen für Klassen
• Externes Tool für die einfache Implementierung von Klassen
Weitere Informationen finden Sie unter http://ooc-coding.sourceforge.net/ .
quelle
Es scheint, als würden Leute versuchen, den C ++ - Stil mit C zu emulieren. Meiner Meinung nach ist objektorientiertes Programmieren C wirklich strukturorientiertes Programmieren. Sie können jedoch Dinge wie späte Bindung, Kapselung und Vererbung erreichen. Für die Vererbung definieren Sie explizit einen Zeiger auf die Basisstrukturen in Ihrer Unterstruktur, und dies ist offensichtlich eine Form der Mehrfachvererbung. Sie müssen auch feststellen, ob Ihre
kompilieren mit
c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj
.Der Rat ist also, sich an einen reinen C-Stil zu halten und nicht zu versuchen, einen C ++ - Stil zu erzwingen. Auch auf diese Weise eignet sich eine sehr saubere Methode zum Erstellen einer API.
quelle
Unter http://slkpg.byethost7.com/instance.html finden Sie eine weitere Neuerung von OOP in C. Es werden Instanzdaten für die Wiedereintritte nur mit nativem C hervorgehoben. Die Mehrfachvererbung erfolgt manuell mithilfe von Funktionsumbrüchen. Die Typensicherheit bleibt erhalten. Hier ist ein kleines Beispiel:
quelle
Ich bin etwas spät zur Party, aber ich möchte meine Erfahrungen zu diesem Thema teilen: Ich arbeite heutzutage mit eingebetteten Dingen, und der einzige (zuverlässige) Compiler, den ich habe, ist C, sodass ich objektorientiert anwenden möchte Ansatz in meinen eingebetteten Projekten in C.
Die meisten Lösungen, die ich bisher gesehen habe, verwenden Typecasts stark, sodass wir die Typensicherheit verlieren: Der Compiler hilft Ihnen nicht, wenn Sie einen Fehler machen. Dies ist völlig inakzeptabel.
Anforderungen, die ich habe:
Ich habe meinen Ansatz in diesem Artikel ausführlich erläutert: Objektorientierte Programmierung in C ; Außerdem gibt es ein Dienstprogramm zur automatischen Generierung von Boilerplate-Code für Basis- und abgeleitete Klassen.
quelle
Ich habe eine kleine Bibliothek gebaut, in der ich das ausprobiert habe und für mich funktioniert es wirklich gut. Also dachte ich, ich teile die Erfahrung.
https://github.com/thomasfuhringer/oxygen
Die Einzelvererbung kann ganz einfach mithilfe einer Struktur implementiert und für jede andere untergeordnete Klasse erweitert werden. Eine einfache Umwandlung in die übergeordnete Struktur ermöglicht die Verwendung übergeordneter Methoden für alle Nachkommen. Solange Sie wissen, dass eine Variable auf eine Struktur verweist, die diese Art von Objekt enthält, können Sie jederzeit in die Stammklasse umwandeln und eine Selbstbeobachtung durchführen.
Wie bereits erwähnt, sind virtuelle Methoden etwas schwieriger. Aber sie sind machbar. Um die Dinge einfach zu halten, verwende ich einfach eine Reihe von Funktionen in der Klassenbeschreibungsstruktur, die jede untergeordnete Klasse kopiert und bei Bedarf einzelne Slots neu auffüllt.
Die Mehrfachvererbung wäre ziemlich kompliziert zu implementieren und hat erhebliche Auswirkungen auf die Leistung. Also lasse ich es. Ich halte es in einigen Fällen für wünschenswert und nützlich, die realen Lebensumstände sauber zu modellieren, aber in wahrscheinlich 90% der Fälle deckt die Einzelvererbung die Bedürfnisse ab. Und Einzelvererbung ist einfach und kostet nichts.
Auch die Typensicherheit ist mir egal. Ich denke, Sie sollten sich nicht auf den Compiler verlassen, um Programmierfehler zu vermeiden. Und es schützt Sie sowieso nur vor einem kleinen Teil der Fehler.
In einer objektorientierten Umgebung möchten Sie normalerweise auch die Referenzzählung implementieren, um die Speicherverwaltung so weit wie möglich zu automatisieren. Daher habe ich auch einen Referenzzähler in die Stammklasse "Objekt" und einige Funktionen zum Einkapseln der Zuordnung und Freigabe des Heapspeichers eingefügt.
Es ist alles sehr einfach und schlank und gibt mir das Wesentliche von OO, ohne mich zu zwingen, mich mit dem Monster zu befassen, das C ++ ist. Und ich behalte die Flexibilität, in C Land zu bleiben, was unter anderem die Integration von Bibliotheken von Drittanbietern erleichtert.
quelle
Ich schlage vor, Objective-C zu verwenden, eine Obermenge von C.
Während Objective-C 30 Jahre alt ist, können Sie eleganten Code schreiben.
http://en.wikipedia.org/wiki/Objective-C
quelle
Ja, aber ich habe noch nie jemanden gesehen, der versucht hat, mit C. irgendeine Art von Polymorphismus zu implementieren.
quelle