Ist STL mit OO implementiert?

8

In STL sind verschiedene Entwurfsmuster wie Adapter und Iterator implementiert.

Bedeutet das, dass STL mit OO-Konzepten implementiert wird?
Welche Beziehung besteht zwischen OO und Vorlagenteilen von C ++?

Ich habe erfahren, dass die Funktion eines virtuellen Mitglieds, die die OO rechtfertigt, der Vorlage widerspricht. Ist das richtig?

Upton
quelle
4
Der Designer der STL ist bekanntermaßen Anti-OO. en.wikipedia.org/wiki/Alexander_Stepanov#Criticism_of_OOP
stonemetal

Antworten:

11

Erstens ist die "STL" kein offizieller Begriff, sondern der Name der Bibliothek, die für die Aufnahme in die C ++ - Standardbibliothek vorgeschlagen wurde, wenn keine Container vorhanden waren. Es bietet im Wesentlichen Container- und Algorithmusvorlagen.

Diese Container- und Algorithmusvorlagen sind ... Vorlagen, sodass sie nach Bedarf Typen erzeugen. Sie sind aus Sicht des Benutzers nicht auf Vererbung angewiesen.

Die Standardbibliothek gibt jedoch im Wesentlichen die Schnittstelle der Bibliothek an, nicht die Implementierung. Viele STL-Implementierungen verwenden ein wenig Objektorientierung in ihrer Implementierung, aber als Benutzer werden Sie es nicht sehen, wenn Sie nicht in den Quellcode Ihrer Implementierung eintauchen (der verfügbar gemacht werden muss, da es sich im Wesentlichen um Vorlagencode handelt).

Ich habe erfahren, dass die Funktion eines virtuellen Mitglieds, die die OO rechtfertigt, der Vorlage widerspricht. Ist das richtig?

Nein, es handelt sich um orthogonale Konzepte, die sehr unterschiedliche Vor- und Nachteile bieten. In C ++ besteht einer der Hauptvorteile bei der Verwendung einer solchen Sprache darin, dass Sie sowohl verfügbar sind als auch eine verwenden und nicht mit der anderen abbrechen. Es ist sogar ein sehr großer Vorteil. Eine der interessantesten Redewendungen in C ++ ist beispielsweise CRTP , das sowohl Vorlagen als auch Vererbung verwendet. Die Idee ist, dass Sie mit dem Vererbungsteil mehrere Typen mit einem gemeinsamen Verhalten und gemeinsamen Daten als Basisklasse erweitern können. Während der Vorlagenteil sicherstellt, dass für jedes untergeordnete Element bestimmte Basisklassen generiert werden, ist es unmöglich, einen Zeiger auf alle Klassen zu haben, die die CRTP-Klasse als Basis verwenden. Dies ist äußerst nützlich und erlaubt es nicht, mit der Vererbung herumzuspielen, wo es keine geben sollte.

Ich habe auch sehr generische Ereignisverteilungssysteme implementiert, die weder Ereignistypen noch Listenertypen kannten, sondern intern dynamischen und statischen Code kombinierten, der es zusammen ermöglichte, die richtigen internen Typen zu generieren, die den richtigen Laufzeittypen entsprechen.

Und das ist der Punkt: Sie brauchen nicht immer "Objektorientierung". Tatsächlich müssen Sie die meiste Zeit, wenn Sie sie überhaupt nicht benötigen, einige Typen definieren und sie direkt als unterschiedlichen Teil einer abstrakten Engine (Komposition) verwenden. Sie benötigen nicht immer generischen Code, auch Vorlagen genannt. Manchmal muss eine Funktion verallgemeinert werden, um sie auf mehrere nicht verwandte Typen anzuwenden. Wenn sie verwandt sind, können Sie stattdessen ihre Basisklasse verwenden und benötigen keine Vorlagen.

Sie haben unterschiedliche Vorteile und völlig unterschiedliche Kosten, sodass sie gut kombiniert werden können, um komplexe Probleme zu lösen.

STL ist ein gutes Beispiel für ein Problem, bei dem es hauptsächlich darum geht, Typen (Container) und Funktionen (Algorithmen) bereitzustellen, die sich auf einen bestimmten Typ beziehen, anstatt auf eine Hierarchie von Laufzeitobjekten. In der Standardbibliothek werden Streams auf eine für die Objektorientierung typische Weise erstellt: Es handelt sich um eine Hierarchie von Stream-Klassen, die verschiedene Funktionen ausführt, um eine Sub-Stream-Klasse zu definieren, die unterschiedliche Verhaltensweisen / Kapazitäten kombiniert. Dort ist die Objektorientierung nützlich, auch wenn einige Leute es vorziehen würden, wenn sie eher der STL ähnelt (ich bin kein Spezialist auf diesem Gebiet).

Stellen Sie sich diese also als sehr unterschiedliche Werkzeuge vor, als Schraubenzieher und Hammer. In C ++ können Sie nicht nur an ein Tool denken.

Klaim
quelle
8

Tatsächlich führte die STL das Paradigma der generischen Programmierung in den Mainstream ein.

Als ich vor 15 Jahren (von einem Professor) über das objektorientierte Programmierparadigma unterrichtet wurde, wurden mir die drei entscheidenden Säulen Kapselung, Vererbung und Polymorphismus beigebracht (heute sollte letzteres wahrscheinlich als Laufzeitpolymorphismus bezeichnet werden ), während Wikipedia derzeit listet Datenabstraktion, Kapselung, Messaging, Modularität, Polymorphismus und Vererbung als definierende OOP-Merkmale auf. Natürlich verwendet die STL einige davon, wie die Kapselung, aber dann verwendet sie auch Funktionen, die für das Paradigma der strukturierten Programmierung charakteristisch sind . Dennoch würde niemand argumentieren, dass die STL strukturierte Programmierung ist .

Beachten Sie, dass eine der stärksten Funktionen von C ++ die Tatsache ist, dass es viele Programmierparadigmen unterstützt (strukturierte, objektorientierte, generische, funktionale Programmierung und andere) und dass es dort am hellsten leuchtet, wo Sie sie mischen und mischen.

sbi
quelle
7

Um Alexander Stepanov aus seinem STLPort-Interview zu zitieren :

STL ist nicht objektorientiert. Ich denke, dass Objektorientierung fast genauso ein Scherz ist wie künstliche Intelligenz. Ich habe noch keinen interessanten Code gesehen, der von diesen OO-Leuten stammt. [...] Ich finde OOP philosophisch nicht gesund. Es wird behauptet, dass alles ein Objekt ist. Auch wenn es wahr ist, ist es nicht sehr interessant - zu sagen, dass alles ein Objekt ist, sagt überhaupt nichts. Ich finde OOP methodisch falsch.

Eine individuelle Implementierung könnte jedoch stellenweise unter Verwendung von Vererbung und Polymorphismus erfolgen. Ich habe zum Beispiel eine Implementierung gesehen, von der iteratorabgeleitet wurde const_iterator, um die implizite Konvertierung von iteratornach zu unterstützen const_iterator. Die Ableitung ist jedoch nicht charakteristisch für das Design oder wird von diesem verlangt.

Fazit: Während Sie objektorientierten Code verwenden können / könnten, um einige Teile der STL zu implementieren, ist das Design der STL selbst (nachdrücklich) nicht objektorientiert.

Jerry Sarg
quelle
3

Nein, ich würde sagen, die STL ist nicht besonders OO, wenn überhaupt, entspricht sie eher einem funktionalen Programmierstil. Bestimmtes:

  • std :: -Algorithmen sind freie Funktionen, keine Methoden
  • Sie nehmen oft Funktionsobjekte, also :. sind Funktionen höherer Ordnung
  • Sie arbeiten mit jedem Container
  • std :: transform ist map, die X_if-Funktionen sind Filter, std :: accumulate ist fold / redu

Ebenso kann man argumentieren, dass die Container selbst Monaden sind

  • Die Vorlageninstanziierung ist eine Typkonstruktion
  • Die Sequenzen haben mindestens Einheitskonstruktoren, z vector<string>(1,"Foo")
  • fmap ist std :: transform
  • Binden und / oder Verbinden sind implementierbar (obwohl nicht sofort verfügbar)
  • Jede vernünftige Implementierung von Bind / Join würde den Monadengesetzen entsprechen

Bei Ihren anderen Fragen sind die OO-Teile und Vorlagenteile von C ++ getrennt, und virtuelle Funktionen schließen Vorlagen nicht aus. Im Fall der STL verwendet das Design einfach keine virtuellen Funktionen.

jk.
quelle
Freie Funktionen gegen Methoden sind größtenteils eine syntaktische Unterscheidung, und nur weil sie funktional sind, heißt das nicht, dass sie im Gegenteil nicht objektorientiert sind.
Konrad Rudolph
Darüber hinaus können die Algorithmen funktionsfähig sein, aber es gibt keinen Grund zu der Annahme, dass dies std::vector<int>nicht objektorientiert ist.
DeadMG
3

Es hängt davon ab, wen Sie nach einer Definition von OOP fragen, da OOP ein notorisch schlecht definierter Begriff ist und es keinen guten Konsens darüber gibt, was OOP ausmacht und was nicht.

Aus der Sicht einer Java-Person lautet die Antwort wahrscheinlich "Nein", da die Algorithmen- und Containerbibliothek von C ++ sich nicht mit Laufzeitpolymorphismus befasst, keine Klassenvererbung verwendet und die Syntax nicht OOP-y aussieht.

Wenn Sie andererseits eine funktionierende Programmierperson fragen, lautet die Antwort möglicherweise "Ja".

So definiert Wikipedia OOP:

Objektorientierte Programmierung (OOP) ist ein Programmierparadigma, bei dem "Objekte" - Datenstrukturen, die aus Datenfeldern und Methoden zusammen mit ihren Interaktionen bestehen - zum Entwerfen von Anwendungen und Computerprogrammen verwendet werden. Programmiertechniken können Merkmale wie Datenabstraktion, Kapselung, Messaging, Modularität, Polymorphismus und Vererbung umfassen. Viele moderne Programmiersprachen unterstützen jetzt OOP, zumindest als Option.

All dies wird in der Standardbibliothek von C ++ und insbesondere in dem Teil, der sich mit Containern und Algorithmen befasst, realisiert oder unterstützt. Insbesondere stärken die Algorithmen die Kapselung und Abstraktion (und damit die Modularität) und sind durch die Verwendung von Vorlagen polymorph.

Konrad Rudolph
quelle
Abgesehen davon, dass Sie die Vererbung für diese Container verwenden sollten, was eine der Hauptfunktionen von OOP ist.
sbi
1
@sbi Ich betrachte die Vererbung als roten Hering. Bei OOP geht es eigentlich um Abstraktion und Wiederverwendung von Code, die durch Vererbung erleichtert werden. Die STL bietet beides. Aber gerade die Wikipedia - Definition auf das Schreiben zu erfüllen, die STL - Container werden tatsächlich über Vererbung implementiert (obwohl das natürlich eine Implementierung Detail).
Konrad Rudolph
Vererbung war ein Hauptmerkmal vor Vorlagen. Ich glaube nicht, dass die Verwendung der Vererbung zum Implementieren einer Abstraktion wichtiger ist als die Verwendung von Vorlagen zum Implementieren dieser Abstraktion.
DeadMG
Wenn man allgemein von Vererbung spricht und nicht so, wie es in der C ++ - Sprachsyntax definiert ist, kann man argumentieren, dass der Vektor <int> vom abstrakten Basisklassenvektor geerbt wird. Durch Überlastung von Funktoren und Bedienern wird ein Polymorphismus erzielt, der für den int-Typ spezifisch ist.
@Lundin Stimmt, aber das ist einfach die Abstraktion einer Schnittstelle. Welches ist, was Vererbung auch tut, weshalb ich denke, dass Vererbung nicht betont werden sollte.
Konrad Rudolph
1

Meiner Meinung nach geht es bei STL mehr um Algorithmen über iterierbare Container als um OO.

Es definiert eine gemeinsame Schnittstelle (den Iterator), die implementiert werden soll, um die Algorithmen zu verwenden.

C / C ++ - Iteratoren werden in Java und C # als enumerator / enumeratable bezeichnet

Vielleicht ist STL aspektorientierter als OO.

k3b
quelle
1

Ich habe diese virtuelle Mitgliedsfunktion gelernt, die die OO rechtfertigt

Wo um alles in der Welt hast du das gehört?

Die entscheidenden Grundsätze der Objektorientierung sind Kapselung und Abstraktion. virtualFunktionen sind nur ein Mittel, mit dem dies erreicht wird. Sie sind für die tatsächliche Objektorientierung überhaupt nicht erforderlich. In der Tat ist eine Vorlage ein perfekt geeignetes Mittel. Es ist vielleicht keine Vererbung, aber es ist immer noch eine Art Polymorphismus. Und einige Klassen erfordern keine.

Die Container der Standardbibliothek sind absolut objektorientiert. Sie kapseln alle unnötigen Details von der Schnittstelle und abstrahieren die Implementierung so weit wie möglich.

DeadMG
quelle
Als mir vor 15 Jahren "OO" beigebracht wurde, wurden mir die drei entscheidenden Säulen Kapselung, Vererbung und Polymorphismus beigebracht.
sbi
Vererbung und Polymorphismus sind nur ein Mittel zum Erreichen der Endziele: Kapselung und Abstraktion. Ganz zu schweigen davon, dass Vorlagen zwar keine Vererbung verwenden, aber polymorph sind.
DeadMG
Nun, es wird allgemein gelehrt, wie sbi sagte. Ich stimme Ihnen zu, dass es sich größtenteils um einen roten Hering handelt.
Konrad Rudolph
-1

Die OOP-Implementierung an sich bedeutet nichts, bis Sie nicht definieren, was Sie unter "Objekt" verstehen. Wenn Objekte Werte sind (keine Entitäten, wie die meisten sogenannten OOP-Sprachen, aber C ++ annimmt), dann ist STL OOP, andernfalls nein.

Angenommen, dieses Codefragment:

Person a("joe");
Person b = a;

Sind aund bzwei Darstellungen derselben lebenden Person oder nur zwei lebende Pesons mit demselben Namen?

Was ist das Objekt? a, bOder die lebende Person (en) sie vertreten?

Außerdem ist die C ++ - Vererbung ein technischer Aggregationsmechanismus, der sich von der Objektvererbung (dh einer Abstraktion) unterscheidet. Die beiden können zusammenfallen, wenn Sie eine bestimmte Disziplin auferlegen (wie Objekte, die alle durch Indirektion zugänglich und austauschbar sind - das heißt, alle relevanten Methoden sind virtuell), andernfalls können sie unterschiedliche Ziele ansprechen (C ++ - Vererbung ist nichts anderes als eine "implizite Komposition"). )

Vorlagen können auch (über Spezialisierung) einen "Substitutions" -Mechanismus bieten, der auf statischen Typen und nicht auf dynamischen Typen (basierend auf virtuellen Funktionen) basiert, und in diesem Sinne - wenn zur Kompilierungszeit dieselbe Disziplin verwendet wird - eine OOP zur Kompilierungszeit bereitstellen.

Im Wesentlichen ist keines der C ++ - Aggregations- und Dispatching-Schemata für sich genommen OOP oder rechtfertigt OOP. Sie können auch andere Dinge tun. OOP ist eine abstrakte Methode, um Objekte miteinander zu beschreiben und in Beziehung zu setzen. Diese Beziehung kann der Vererbung und dem virtuellen Versand zugeordnet werden, wenn die Objekttypen von der Laufzeitausführung abhängen, oder sie kann der Vorlagenspezialisierung und impliziten Konvertierungen zugeordnet werden, wenn die Objekttypen während der Kompilierung definiert werden können. Vererbung kann nur eine Möglichkeit sein, eine implizite Konvertierung zwischen Referenzen und Zeigern bereitzustellen.

Emilio Garavaglia
quelle
Vererbung ist immer auch ein Aggregationsmechanismus, nicht nur in C ++.
Konrad Rudolph
Ich muss hier abstimmen. Selbst wenn virtuelle Methoden ignoriert werden, weist die Komposition gravierende Unterschiede zur Vererbung auf.
DeadMG
@KonradRudolph: stimmt, aber die Frage betrifft C ++.
Emilio Garavaglia
@DeadMG: Bitte beachten Sie, dass die Bedeutung des Begriffs "Zusammensetzung" außerhalb der OOP-Terminologie auch im Klartext eine genaue Bedeutung hat. Und Vererbung (abgesehen von der virtuellen Methode) ist nichts anderes als "mit einem unbenannten Mitglied komponieren". Ich verstehe vollkommen, dass OOP-Integralisten diese Fakten nicht mögen, aber C ++ ist nicht nur eine OOP-Sprache, und Vererbung sowie Klassenzusammensetzung dienen nicht nur OOP "ist eine" und "hat eine" Beziehung. ...
Emilio Garavaglia
... Es gibt einen Unterschied zwischen der OOP-Terminologie und der C ++ - Terminologie. Früher, als C ++ keine andere Paradigmenunterstützung hatte als Vererbung und virtuelle Methoden (keine Tempates und keine Lambdas), konnten die beiden Begriffe absichtlich verwechselt und anstelle einer anderen verwendet werden, aber heutzutage wurde die OOP-Vererbung reduziert, um nur die OOP zu implementieren Substitutionsprinzip ist bewusst die Sprache zu kastrieren.
Emilio Garavaglia