Warum wird C nicht als objektorientierte Sprache betrachtet?


92

Es scheint, dass C seine eigenen Quasi-Objekte wie "Strukturen" hat, die als Objekte betrachtet werden können (auf der höheren Ebene, wie wir es normalerweise denken würden).

Und auch C-Dateien selbst sind grundsätzlich separate "Module", oder? Sind Module dann nicht auch so etwas wie 'Objekte'? Ich bin verwirrt, warum C, das C ++ so ähnlich zu sein scheint, als "prozedurale" Sprache auf niedriger Ebene betrachtet wird, während C ++ auf hoher Ebene "objektorientiert" ist.

* edit: (Klarstellung) warum und wo wird die Linie gezogen, für was ist ein 'Objekt' und was nicht?


40
Alle - warum stimmen die Abwärtsstimmen? Es ist eine grundlegende Frage, aber keine schlechte.
Jon Hopkins

7
Sie können OO-Prinzipien effektiv in C verwenden (und Leute, die guten C-Code schreiben, tun dies normalerweise), aber die Sprache ist nicht darauf ausgelegt, es einfach zu machen, wie dies bei vielen neueren Sprachen der Fall ist.
Asveikau

5
C hat einfach einen anderen, einfacheren und (um ehrlich zu sein) besser definierten Ansatz für die Datenabstraktion (zumindest innerhalb der Open-Source-Community). C ++ ist in der Regel ein Kraftpaket für Abstraktionen und bietet viele großartige Möglichkeiten, muss jedoch verstehen, wie man sie nicht richtig einsetzt, was häufig in gängigen Programmen nicht der Fall ist. Siehe meine vollständige Antwort für weitere Details.
Yam Marcovic

1
Kurz: Strukturen können keine Methoden haben. (Der Zeiger auf eine Funktion schneidet sie nicht ganz ab.)
SF.

1
Es ist mit einigen Schwierigkeiten möglich, objektbasierte Programmierung in C durchzuführen. Aber das macht es nicht objektorientiert .
Wedge

Antworten:


101

Es scheint, dass C seine eigenen Quasi-Objekte wie "Strukturen" hat, die als Objekte betrachtet werden können

Lassen Sie uns gemeinsam die Wikipedia-Seite zur objektorientierten Programmierung lesen und die Merkmale von C-Stil-Strukturen abhaken, die dem entsprechen, was traditionell als objektorientierter Stil angesehen wird:

(OOP) ist ein Programmierparadigma, das "Objekte" verwendet - Datenstrukturen, die aus Datenfeldern und Methoden zusammen mit ihren Wechselwirkungen bestehen

Bestehen C-Strukturen aus Feldern und Methoden mit ihren Wechselwirkungen ? Nein.

Programmiertechniken können Merkmale wie Datenabstraktion, Kapselung, Nachrichtenübermittlung, Modularität, Polymorphismus und Vererbung umfassen.

Machen C-Strukturen all diese Dinge auf "erstklassige" Weise? Nein, die Sprache wirkt sich bei jedem Schritt gegen Sie aus.

Der objektorientierte Ansatz ermutigt den Programmierer, Daten an Stellen zu platzieren, auf die der Rest des Programms nicht direkt zugreifen kann

Tun C structs dies? Nein.

Ein objektorientiertes Programm enthält normalerweise verschiedene Objekttypen, wobei jeder Typ einer bestimmten Art komplexer Daten entspricht, die verwaltet werden sollen, oder vielleicht einem Objekt oder Konzept der realen Welt

Tun C structs dies? Ja.

Man kann sich vorstellen, dass Objekte ihre Daten in eine Reihe von Funktionen einschließen, mit denen sichergestellt wird, dass die Daten ordnungsgemäß verwendet werden

Nein.

Jedes Objekt kann Nachrichten empfangen, Daten verarbeiten und Nachrichten an andere Objekte senden

Kann eine Struktur selbst Nachrichten senden und empfangen? Kann es Daten verarbeiten? Nein.

OOP-Datenstrukturen neigen dazu, "ihre eigenen Operatoren mit sich zu führen"

Passiert das in C? Nein.

Dynamischer Versand ... Kapselung ... Subtyp Polymorphismus ... Objektvererbung ... Offene Rekursion ... Klassen von Objekten ... Instanzen von Klassen ... Methoden, die auf die angehängten Objekte einwirken ... Nachrichtenübergabe .. Abstraktion

Gibt es eines dieser Merkmale von C-Strukturen? Nein.

Welche Eigenschaften von Strukturen halten Sie für "objektorientiert"? Weil ich nichts anderes finden kann als die Tatsache, dass Strukturen Typen definieren .

Jetzt können Sie natürlich Strukturen mit Feldern erstellen, die auf Funktionen verweisen. Sie können Strukturen mit Feldern versehen, die Zeiger auf Arrays von Funktionszeigern sind, die virtuellen Methodentabellen entsprechen. Und so weiter. Sie können natürlich C ++ in C emulieren . Aber das ist eine sehr unidiomatische Art, in C zu programmieren. Sie wären besser dran, wenn Sie nur C ++ verwenden.

Und auch C-Dateien selbst sind grundsätzlich separate "Module", oder? Sind Module dann nicht auch so etwas wie 'Objekte'?

An welche Eigenschaften von Modulen denken Sie, dass sie sich wie Objekte verhalten? Unterstützen Module Abstraktion, Kapselung, Messaging, Modularität, Polymorphismus und Vererbung?

Abstraktion und Verkapselung sind ziemlich schwach. Offensichtlich sind Module modular aufgebaut; Deshalb heißen sie Module. Messaging? Nur in dem Sinne, dass ein Methodenaufruf eine Nachricht ist und Module Methoden enthalten können. Polymorphismus? Nee. Erbe? Nee. Module sind ziemlich schwache Kandidaten für "Objekte".


15
Ich bin anderer Meinung, dass "C ++ emulieren" (Ihr Begriff) nicht idiomatisch ist. Ein Gegenbeispiel wäre, wie ein Betriebssystemkernel normalerweise Dateioperationen implementiert - nehmen Sie Linux als Beispiel, wo Sie Strukturen voller Funktionszeiger haben. Es mag sich um etwas "domänenspezifische" Redewendungen handeln (z. B. um das Schreiben von Treibern unter * nix), aber sie sind erkennbar und erledigen die Arbeit für einige Zwecke sauber genug. Es gibt auch einige Beispiele für Benutzermodusbibliotheken, die eine ausreichende Vorstellung von OO haben. Nimm Gtk + und die Bibliotheken, von denen es abhängt. Nennen Sie es hacky und Sie haben vielleicht Recht, aber es ist nicht schrecklich, mit diesen zu arbeiten
asveikau

5
@asveikau: Bedeutet die Vorstellung, dass eine Praxis ungewöhnlich (auch wenn sie nicht unbekannt ist) und "hacky" ist, nicht, dass sie per definitionem nicht idiomatisch ist?
Adam Robinson

19
@asveikau: Klar, es gibt Dinge, die Sie tun können, um C-Programme stilvoller zu machen. Aber wie Sie sagen, erfordert dies Disziplin. Die Sprachmerkmale selbst führen Sie natürlich nicht zu Kapselung, Polymorphismus, Klassenvererbung usw. Vielmehr kann der Entwickler der Sprache dieses Muster auferlegen. Das bedeutet nicht, dass Strukturen logisch dasselbe sind wie Objekte. Sie können auch in Lisp einen OO-Stil programmieren, aber das bedeutet nicht, dass Konsolen Objekte sind.
Eric Lippert

3
@asveikau, darf ich vorschlagen, dass Ihre (falsche) Interpretation von "Redewendung" als "der eigenen" mild ... idiosynkratisch ist? :)
Benjol

8
@BillK: Strukturen können in C keinen Code enthalten. Strukturen können Funktionszeiger enthalten , bei denen es sich um Daten handelt . Funktionszeiger sind kein Code . Code ist ein Textartefakt, das von einem Programmierer erstellt wurde.
Eric Lippert

46

Das Schlüsselwort ist "orientiert", nicht "Objekt". Selbst C ++ - Code, der Objekte verwendet, diese aber wie Strukturen verwendet, ist nicht objektorientiert .

C und C ++ können beide OOP ausführen (abgesehen von keiner Zugriffskontrolle in C), aber die Syntax dafür ist unpraktisch (gelinde gesagt), während die Syntax in C ++ es sehr einladend macht. C ist prozedural orientiert, während C ++ trotz nahezu identischer Kernfähigkeiten in dieser Hinsicht objektorientiert ist.

Code, der Objekte zum Implementieren von Designs verwendet, die nur mit Objekten ausgeführt werden können (was normalerweise bedeutet, dass der Polymorphismus ausgenutzt wird), ist objektorientierter Code. Code, der Objekte so wenig wie Datenmengen verwendet, selbst wenn Vererbung in einer objektorientierten Sprache verwendet wird, ist eigentlich nur prozeduraler Code, der komplizierter ist, als er sein muss. Code in C, der Funktionszeiger verwendet, die zur Laufzeit mit Strukturen voller Daten geändert werden, führt zu einem Polymorphismus und kann sogar in einer prozeduralen Sprache als "objektorientiert" bezeichnet werden.


2
+1 Für das Zeigen kann unser C OO sein. Es ist nicht bequem, aber es kann getan werden.
Dietbuddha

Es ist einfacher, Objekte in VBA zu erstellen, aber ich würde es auch nicht als objektorientiert betrachten.
JeffO

VBA nenne ich "objektbasiert". Es werden Objekte verwendet, aber nicht polymorph, und in der kleinen Arbeit, die ich darin geleistet habe, bin ich mir nicht sicher, ob Sie überhaupt Polymorphismus machen können, egal welche Art von Code-Akrobatik Sie versuchen. Es ist im Grunde eine prozedurale Sprache mit Kapselung.
kylben

2
Die meisten Sprachen können als OO, funktional oder so ziemlich jede Art von Sprache fungieren. Der Unterschied ist der "Orientierte" und ich hatte es noch nie so gehört. Ich wünschte, ich könnte dreimal darüber abstimmen und es akzeptieren, es ist die richtige Antwort.
Bill K

1
@kylben Es wäre nicht zu aufwändig, SQL-Code in der Tabelle zu speichern, dann zu extrahieren und auszuführen (die Tabelle zum Objekt zu machen). Es wäre ein interessantes Experiment. Eigentlich ist es ein wenig verlockend ...
Bill K

19

Basierend auf den höchsten Prinzipien:

Ein Objekt ist eine Verkapselung von Daten und Verhalten auf eine miteinander verknüpfte Art und Weise, so dass sie als Ganzes funktionieren, das mehrere Male instanziiert und als Black Box bearbeitet werden kann, wenn Sie die externe Schnittstelle kennen.

Strukturen enthalten Daten, aber kein Verhalten und können daher nicht als Objekte betrachtet werden.

Module enthalten sowohl Verhalten als auch Daten, sind jedoch nicht so eingekapselt, dass beide in Beziehung stehen und mit Sicherheit nicht mehrmals instanziiert werden können.

Und das ist, bevor Sie auf Vererbung und Polymorphismus kommen ...


Warum hängen Verhalten und Daten in Modulen nicht zusammen? Sind Mitgliedsfunktionen nicht im Grunde genommen das 'Verhalten' der Daten, die innerhalb des Moduls existieren?
Dunkler Templer

4
Das Problem ist, dass sie nicht eingekapselt sind, nicht dass sie nicht verwandt sind.
Eoin Carroll

Tatsächlich konzentrieren sich Objekte hauptsächlich auf das Verhalten , nicht auf Daten. Daten sind / sollten Bürger zweiter Klasse in OOP sein. Strukturen konzentrieren sich stattdessen auf Daten und haben kein Verhalten.
Sklivvz

1
@ Dark Templar - Was Eoin gesagt hat ... Es liegt in der Natur der Beziehung. Ich kann sehen, woher Sie kommen - Sie könnten Structs in einem Modul sicherlich so verwenden, dass es einige sehr grundlegende Elemente von OO emuliert, aber vieles, was Sie tun würden, würde davon abhängen, dass der Programmierer an einer Menge festhält von selbst auferlegten Regeln, anstatt von der Sprache durchgesetzt zu werden. Und warum sollten Sie sich die Mühe machen? Sie erhalten keinen der Vorteile von OO - beispielsweise keine Vererbung - und schränken sich ein.
Jon Hopkins

Dies ist eine bessere Antwort als die richtige.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzz

6

"structs" sind nur Daten. Der übliche schnelle und schmutzige Test der "Objektorientierung" lautet: "Gibt es eine Struktur, mit der Code und Daten als eine Einheit gekapselt werden können?". C scheitert daran und ist daher prozedural. C ++ besteht diesen Test.


6
Es gibt Workarounds, Strukturen können statische Funktionszeiger auf Memberfunktionen haben. Sie benötigen einen expliziten thisZeiger, aber in diesem Fall sind Daten und Mittel zur Datenverarbeitung in der Struktur gekapselt.
Coder

@Brian Knoblauch: Ist aber eine C-Datei selbst keine Kapselung von Daten und Code ???
Dark Templar

@DarkTemplar In gewisser Hinsicht, ja, aber wenn Sie keine Übersetzungseinheiten erstellen, kompilieren und zur Laufzeit in den laufenden Prozess laden können, ist dies wenig hilfreich.

Übersetzungseinheiten? >. <
Dunkler Templer

@Dark Templer: eine Übersetzungseinheit ist eine Quelldatei und etwas #includehinein d und minus etwas durch die nicht bedingt eingeschlossen entfernt wird ( #if, #ifdefund dergleichen).
David Thornley

5

C, wie C ++, hat die Fähigkeit der Bereitstellung von Datenabstraktion , die eine Sprache der objektorientierten Programmierung Paradigma ist , die vor ihm existierte.

  • C-Strukturen können Daten haben (und das ist ihr Hauptzweck)
  • C-Strukturen können auch Funktionszeiger als Daten definieren
  • C-Strukturen können und werden häufig mit einer Reihe von Funktionen verknüpft, genau wie Methoden. Nur dieser Zeiger wird nicht implizit übergeben. Sie müssen ihn jedoch explizit als erstes Argument für jede Methode angeben, die für die Verarbeitung der angegebenen Struktur entwickelt wurde. C ++ erledigt dies automatisch für Sie, wenn Sie Klassen- / Strukturmethoden definieren und aufrufen .

OOP in C ++ erweitert die Möglichkeiten, Daten zu abstrahieren. Einige sagen, dass es schädlich ist , während andere es als ein gutes Werkzeug betrachten, wenn es richtig verwendet wird.

  • C ++ impliziert diesen Zeiger, indem der Benutzer ihn nicht an "Methoden der Klasse / Struktur" übergeben muss, solange der Typ (zumindest teilweise) identifiziert werden kann.
  • Mit C ++ können Sie den Zugriff auf bestimmte Methoden (Klassenfunktionen) einschränken und somit "defensives Programmieren" oder "idiotensicher" machen.
  • C ++ fördert Abstraktionen, indem es durch Einführung eine stärkere Typensicherheit bietet
    1. Der neue Operator anstelle von malloc + cast
    2. Vorlagen anstelle von ungültigen Zeigern
    3. Inline-Funktionen , die anstelle von Makros typisierte Werte empfangen
    4. Eingebauter Polymorphismus, den Sie nicht selbst implementieren müssen, mit dem Sie Abstraktionshierarchien , Verträge und Spezialisierungen erstellen können .

Sie werden jedoch viele C-Hacker finden, die predigen, dass C genau die richtige Menge an Abstraktion kann und dass der von C ++ verursachte Overhead sie nur davon abhält, das eigentliche Problem zu lösen.

Ineffiziente abstrahierte Programmiermodelle, bei denen Sie zwei Jahre später bemerken, dass einige Abstraktionen nicht sehr effizient waren, aber jetzt hängt Ihr gesamter Code von all den netten Objektmodellen ab, die ihn umgeben, und Sie können es nicht reparieren, ohne Ihre App neu zu schreiben. - Linus Torvalds

Andere neigen dazu, es ausgewogener zu betrachten und sowohl die Vorteile als auch die Nachteile zu akzeptieren.

C macht es leicht, sich in den Fuß zu schießen; C ++ macht es schwieriger, aber wenn Sie dies tun, wird Ihnen das ganze Bein weggeblasen. -- Bjarne Stroustrup


2

Sie müssen sich die andere Seite der Medaille ansehen: C ++.

In OOP denken wir an ein abstraktes Objekt (und entwerfen das Programm entsprechend), zum Beispiel ein Auto, das anhalten, beschleunigen, nach links oder rechts abbiegen kann usw. Eine Struktur mit einem Bündel von Funktionen passt einfach nicht zum Konzept.

Bei "echten" Objekten müssen wir zum Beispiel die Mitglieder verbergen, oder wir können auch eine Vererbung mit einer echten "ist eine" Beziehung und vielem mehr haben.

NACH DEM LESEN DER KOMMENTARE: Nun, es ist richtig, dass (fast) alles mit C gemacht werden kann (das ist immer wahr), aber auf den ersten Blick dachte ich, dass das, was c von c ++ trennt, die Art ist, wie Sie beim Entwerfen eines Programms denken.

Das einzige, was wirklich den Unterschied ausmacht, ist das Auferlegen von Richtlinien durch den Compiler . dh rein virtuelle Funktion, und so weiter. Diese Antwort wird sich jedoch nur auf technische Probleme beziehen, aber ich denke, der Hauptunterschied (wie erwähnt) ist die ursprüngliche Art und Weise, wie Sie beim Codieren denken, da C ++ Ihnen eine besser eingebaute Syntax für solche Dinge bietet, anstatt OOP in zu tun ein etwas ungeschickter Weg in C.


Sie sind sich nicht sicher, warum eine Struktur mit einem "Funktionsbündel" nicht zum Konzept passt? +1 für die Antwort aber
Dark Templar

1
Abgesehen von der Zugriffskontrolle (privat / geschützt / öffentlich) kann alles andere mit structs erledigt werden.
Coder

1
@DarkTemplar: Nun, Sie können versuchen, OOP in C zu emulieren (Leute haben tatsächlich E-Books zu diesem Thema geschrieben und tun dies in der realen Welt, wenn auch sehr selten), wie Sie es mit der Emulation von funktionaler Programmierung in Java versuchen können. C bietet jedoch keine Hilfe, daher ist C nicht objektorientiert .

1

Du hast es selbst gesagt. Während C Dinge hat, die Objekten ähneln, sind sie immer noch keine Objekte, und deshalb wird C nicht als OOP-Sprache betrachtet.


1
Nun, ich denke die Frage ist: Warum und wo wird die Linie gezogen für was ist ein Objekt und was nicht?
Dark Templar

1

Objektorientiert bezieht sich sowohl auf ein Architekturmuster (oder sogar ein Metamuster) als auch auf die Sprachen, die Funktionen enthalten, die bei der Implementierung oder Verwendung dieses Musters hilfreich sind.

Sie können ein "OO" -Design implementieren (Gnome-Desktop ist vielleicht das beste Beispiel für OO in reinem C). Ich habe dies sogar mit COBOL gesehen!

In der Lage zu sein, eine OO-Entwurfsdosis zu implementieren, macht die Sprache OO jedoch nicht. Puristen würden argumentieren, dass Java und C ++ nicht wirklich OO sind, da Sie die grundlegenden "Typen" wie "int" und "char" nicht überschreiben oder erben können und Java die Mehrfachvererbung nicht unterstützt. Da sie jedoch die am häufigsten verwendeten OO-Sprachen sind und die meisten der Paradigmen unterstützen, werden sie von den meisten "echten" Programmierern, die für die Erstellung von Arbeitscode bezahlt werden, als OO-Sprachen betrachtet.

C hingegen unterstützt nur Strukturen (wie COBOL, Pascal und Dutzende anderer prozeduraler Sprachen). Sie könnten argumentieren, dass Mehrfachvererbung dadurch unterstützt wird, dass Sie jede Funktion für jedes Datenelement verwenden können, aber die meisten würden dies eher als Fehler ansehen als eine Funktion.


0

Schauen wir uns einfach die Definition von OO an:

  • Messaging
  • Verkapselung
  • Späte Bindung

C bietet keine dieser drei. Insbesondere wird Messaging nicht bereitgestellt , was das wichtigste ist.


1
Ich denke, ich würde dem nicht zustimmen müssen. Sie können mit Sicherheit Messaging in C verwenden - arbeiten Sie mit Objective C-APIs von C und stellen Sie fest, dass dies gründlich durchgeführt werden kann. Eine späte Bindung kann über Funktionszeiger erfolgen, aber Sie erhalten nicht viel syntaktischen Zucker, um dies zu verbergen. (Kapselung ist in C eigentlich einfach; Zeiger auf unvollständige Strukturtypen machen den Job perfekt.)
Donal Fellows

Vererbung wird auch in OO als wichtig angesehen, und C tut das nicht. Der Kapselung in C am nächsten kommen separate Dateien, die interne ( static) Funktionen und Datenelemente haben können.
David Thornley

@DonalFellows, die tatsächliche Nachrichtenübergabe in Objective-C kann problemlos als C99-Makro implementiert werden. Das Einzige, was der Compiler tun muss, ist, dass er alle erforderlichen Strukturen statisch aus wenigen Zeilen Code auf hoher Ebene generiert. Die meisten, wenn nicht alle Funktionen sind über die C-API verfügbar.
11.

0

Es gibt eine Reihe von Hauptbestandteilen für OO, aber die großen sind, dass die Mehrheit des Codes nicht weiß, was sich in einem Objekt befindet (sie sehen die Oberflächenschnittstelle, nicht die Implementierung), dass der Status eines Objekts eine verwaltete Einheit ist (dh, wenn das Objekt aufhört zu sein, so tut dies auch sein Zustand), und wenn ein Code eine Operation an einem Objekt aufruft, tun sie dies, ohne genau zu wissen, was diese Operation ist oder beinhaltet (alles, was sie tun, ist einem Muster zu folgen, um a zu werfen) "Nachricht" über die Mauer).

C macht die Verkapselung ganz gut; Code, der die Definition einer Struktur nicht erkennt, kann (zu Recht) nicht in sie hineinsehen. Dazu müssen Sie lediglich eine Definition wie diese in eine Header-Datei einfügen:

struct FooImpl;
typedef struct FooImpl *Foo;

Natürlich wird eine Funktion benötigt, die Foos erstellt (dh eine Factory) und die einen Teil der Arbeit an das zugewiesene Objekt selbst delegiert (dh über eine "Konstruktor" -Methode) und auch eine Möglichkeit hat das Objekt wieder zu entsorgen (während es über seine "Destruktor" -Methode bereinigt wird), aber das sind Details.

Der Methodenversand (dh das Versenden von Nachrichten) kann auch über die Konvention erfolgen, dass das erste Element der Struktur tatsächlich ein Zeiger auf eine Struktur voller Funktionszeiger ist und dass jeder dieser Funktionszeiger ein Fooals erstes Argument verwenden muss. Beim Versand muss dann die Funktion nachgeschlagen und mit dem richtigen Argument umgeschrieben werden, was mit einem Makro und ein wenig List nicht so schwer zu tun ist . (Diese Funktionstabelle ist der Kern dessen, was eine Klasse in einer Sprache wie C ++ wirklich ist.)

Darüber hinaus bedeutet dies auch eine späte Bindung: Der Versandcode weiß nur, dass er einen bestimmten Offset in einer Tabelle aufruft, auf die das Objekt zeigt. Dies muss nur während der Zuweisung und Initialisierung des Objekts eingestellt werden. Es ist möglich, mit noch komplexeren Versandschemata zu arbeiten, die Ihnen mehr Laufzeitdynamik (zu einem Preis von Geschwindigkeit) verschaffen, aber sie sind Kirschen über dem Grundmechanismus.

Dies bedeutet jedoch nicht, dass C eine OO-Sprache ist. Der Schlüssel ist, dass C Sie die ganze knifflige Arbeit, die Konventionen und den Versandmechanismus selbst zu schreiben, überlässt (oder eine Bibliothek von Drittanbietern verwendet). Das ist viel Arbeit. Es bietet auch keine syntaktische oder semantische Unterstützung, so dass die Implementierung eines vollständigen Klassensystems (mit Dingen wie Vererbung) unnötig schmerzhaft wäre. Wenn Sie sich mit einem komplexen Problem befassen, das durch ein OO-Modell gut beschrieben wird, ist eine OO-Sprache beim Schreiben der Lösung sehr hilfreich. Die zusätzliche Komplexität kann gerechtfertigt sein.


0

Ich denke, C ist vollkommen in Ordnung und anständig, um objektorientierte Konzepte zu implementieren, achselzucken . Die meisten meiner Ansicht nach bestehenden Unterschiede zwischen der Untergruppe der objektorientierten Sprachen mit gemeinsamem Nenner sind aus meiner pragmatischen Sicht geringfügig und syntaktisch.

Beginnen wir zum Beispiel mit dem Verstecken von Informationen. In C können wir dies erreichen, indem wir einfach die Definition einer Struktur verbergen und mit undurchsichtigen Zeigern arbeiten. Das modelliert effektiv die publicvs. privateUnterscheidung von Datenfeldern, wie wir sie mit Klassen erhalten. Und es ist einfach genug und kaum anti-idiomatisch, da die Standard-C-Bibliothek in hohem Maße darauf angewiesen ist, Informationen zu verbergen.

Natürlich verlieren Sie die Möglichkeit, die genaue Speicherzuordnung der Struktur mithilfe von undurchsichtigen Typen einfach zu steuern, aber das ist nur ein bemerkenswerter Unterschied zwischen beispielsweise C und C ++. C ++ ist definitiv ein überlegenes Werkzeug, wenn es darum geht, objektorientierte Konzepte über C zu programmieren und dabei die Kontrolle über Speicherlayouts zu behalten. Dies bedeutet jedoch nicht unbedingt, dass Java oder C # C in dieser Hinsicht überlegen sind, da diese beiden Funktionen Sie überzeugen verlieren vollständig die Fähigkeit zu steuern, wo Objekte im Speicher zugeordnet sind.

Und wir müssen eine Syntax verwenden, fopen(file, ...); fclose(file);die sich von der von file.open(...); file.close();Big Whoop unterscheidet. Wen interessiert das schon? Vielleicht nur jemand, der sich in seiner IDE stark auf die automatische Vervollständigung stützt. Ich gebe zu, dass dies aus praktischer Sicht eine sehr nützliche Funktion sein kann, aber möglicherweise keine, die eine Diskussion darüber erfordert, ob eine Sprache für OOP geeignet ist.

Uns fehlt die Fähigkeit, protectedFelder effektiv umzusetzen . Ich werde dort total einreichen. Ich glaube jedoch nicht, dass es eine konkrete Regel gibt, die besagt: " Alle OO-Sprachen sollten über eine Funktion verfügen, die es Unterklassen ermöglicht, auf Mitglieder einer Basisklasse zuzugreifen, auf die normale Clients immer noch nicht zugreifen sollten ." Außerdem sehe ich selten Anwendungsfälle für geschützte Mitglieder, die zumindest nicht ein bisschen misstrauisch sind, eine Wartungshürde zu werden.

Und natürlich müssen wir den OO-Polymorphismus mit Tabellen von Funktionszeigern und Zeigern auf sie "emulieren", um einen dynamischen Versand mit etwas mehr Boilerplate zu ermöglichen, um diese analogen vtablesund vptrs, aber ein bisschen Boilerplate hat mir nie viel Leid bereitet.

Vererbung ist ähnlich. Wir können das leicht durch Komposition modellieren, und bei der internen Arbeitsweise von Compilern läuft es auf dasselbe hinaus. Natürlich verlieren wir die Typensicherheit , wenn wir einen Downcast ausführen möchten , und da würde ich sagen, wenn Sie überhaupt einen Downcast ausführen möchten , verwenden Sie bitte kein C dafür, da die Dinge, die die Leute in C tun, um einen Downcast zu emulieren, fürchterlich sein können Sicherheitsstandpunkt, aber ich möchte, dass die Leute überhaupt nicht niedergeschlagen sind . Typensicherheit ist etwas, das Sie in C leicht übersehen können, da der Compiler so viel Spielraum bietet, um Dinge wie Bits und Bytes zu interpretieren, was die Fähigkeit einbüßt, mögliche Fehler zur Kompilierungszeit abzufangen, aber einige Sprachen als objektorientiert betrachtet werden nicht einmal statisch getippt.

Also keine Ahnung, ich denke es ist in Ordnung. Natürlich würde ich C nicht verwenden, um eine große Codebasis zu erstellen, die den SOLID-Prinzipien entspricht, aber dies liegt nicht unbedingt an den Mängeln in der objektorientierten Front. Viele der Funktionen, die ich vermissen würde, wenn ich versuchen würde, C für einen solchen Zweck zu verwenden, würden mit Sprachfunktionen zusammenhängen, die nicht direkt als Voraussetzung für OOP angesehen werden, wie z. B. starke Typensicherheit, Destruktoren, die automatisch aufgerufen werden, wenn Objekte den Gültigkeitsbereich verlassen, Operator Überladung, Vorlagen / Generika und Ausnahmebehandlung. Es ist, wenn ich die Zusatzfunktionen vermisse, die ich für C ++ erreiche.


1
Ich bin nicht sicher, wie Konstruktoren nicht als Voraussetzung für OOP angesehen werden konnten. Ein Teil der grundlegenden Essenz der Einkapselung ist die Fähigkeit, Invarianten für ein Objekt sicherzustellen. Und dazu muss das Objekt in diesen Invarianten ordnungsgemäß initialisiert werden können. Das erfordert einen Konstruktor: eine oder mehrere Funktionen, so dass Sie nicht sagen können, dass das Objekt noch existiert, bis mindestens eine von ihnen aufgerufen wurde.
Nicol Bolas

Wenn sich Informationen mit undurchsichtigen Typen verstecken, können sie nur durch das analoge Äquivalent von Funktionen, die als Konstruktoren und Destruktoren dienen, instanziiert und kopiert / geklont und zerstört werden. Es ist nur nicht direkt in die Sprache modelliert und könnte der Form von foo_createund foo_destroyund ähneln foo_clone, zB

In struct Fooeinem solchen Fall müssen wir nur die Invarianten beibehalten , um sicherzustellen, dass die Datenelemente nicht von der Außenwelt abgerufen und mutiert werden können, die von undurchsichtigen Typen (deklariert, aber nicht für die Außenwelt definiert) sofort angegeben wird. Es ist wohl eine stärkere Form des Versteckens von Informationen, die mit der pimplin C ++ vergleichbar ist.

Ja, ich weiß, wie Leute OOP in C implementieren, danke. Mein Punkt war, dass Ihre Aussage, dass Konstruktoren "nicht direkt als Voraussetzung für OOP angesehen werden", falsch ist.
Nicol Bolas

Ich verstehe, ich korrigiere das. Aber könnten wir in diesem Fall sagen, dass C (adäquate?) Unterstützung für Destruktoren und Konstruktoren bietet?

-1

Keine schlechte Frage.

Wenn Sie c als OO-Sprache bezeichnen, müssen Sie auch so gut wie alle prozeduralen Sprachen OO aufrufen. Es würde den Begriff also bedeutungslos machen. c hat keine Sprachunterstützung für OO. If hat Strukturen, aber Strukturen sind typeskeine Klassen.

Eigentlich hat c im Vergleich zu den meisten Sprachen überhaupt nicht viele Funktionen. Es wird hauptsächlich wegen seiner Geschwindigkeit, Einfachheit, Beliebtheit und Unterstützung verwendet, einschließlich Tonnen von Bibliotheken.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.