Warum hat C ++ keine Reflexion?


337

Dies ist eine etwas bizarre Frage. Mein Ziel ist es, die Sprachentwurfsentscheidung zu verstehen und die Reflexionsmöglichkeiten in C ++ zu identifizieren.

  1. Warum hat das C ++ - Sprachkomitee keine Reflexion in der Sprache implementiert? Ist die Reflexion in einer Sprache, die nicht auf einer virtuellen Maschine (wie Java) ausgeführt wird, zu schwierig?

  2. Wenn man Reflection für C ++ implementieren sollte, welche Herausforderungen bestehen dann?

Ich denke, die Verwendung von Reflexion ist bekannt: Editoren können einfacher geschrieben werden, Programmcode wird kleiner, Mocks können für Unit-Tests generiert werden und so weiter. Aber es wäre großartig, wenn Sie auch die Verwendung von Reflexion kommentieren könnten.

Antworten:


631

Es gibt verschiedene Probleme mit der Reflexion in C ++.

  • Es ist eine Menge Arbeit hinzuzufügen, und das C ++ - Komitee ist ziemlich konservativ und verbringt keine Zeit mit radikalen neuen Funktionen, es sei denn, sie sind sich sicher, dass es sich auszahlt. (Es wurde ein Vorschlag zum Hinzufügen eines Modulsystems gemacht, das .NET-Assemblys ähnelt, und obwohl ich denke, dass allgemeiner Konsens darüber besteht, dass dies schön wäre, ist dies im Moment nicht ihre oberste Priorität und wurde bis weit danach zurückgedrängt C ++ 0x. Die Motivation für diese Funktion besteht darin, das #includeSystem loszuwerden , aber es würde auch zumindest einige Metadaten ermöglichen.

  • Sie zahlen nicht für das, was Sie nicht verwenden. Dies ist eine der wichtigsten Designphilosophien, die C ++ zugrunde liegen. Warum sollte mein Code Metadaten enthalten, wenn ich sie möglicherweise nie benötige? Darüber hinaus kann das Hinzufügen von Metadaten den Compiler an der Optimierung hindern. Warum sollte ich diese Kosten in meinem Code bezahlen, wenn ich diese Metadaten möglicherweise nie benötige?

  • Was uns zu einem weiteren wichtigen Punkt führt: C ++ gibt nur sehr wenige Garantien für den kompilierten Code. Der Compiler darf so ziemlich alles tun, was er will, solange die resultierende Funktionalität den Erwartungen entspricht. Zum Beispiel müssen Ihre Klassen nicht tatsächlich dort sein . Der Compiler kann sie optimieren, alles, was sie tun, inline einbinden, und häufig tut er genau das, da selbst einfacher Vorlagencode dazu neigt, einige Vorlageninstanziierungen zu erstellen. Die C ++ - Standardbibliothek basiert auf dieser aggressiven Optimierung. Funktoren sind nur dann performant, wenn der Aufwand für das Instanziieren und Zerstören des Objekts weg optimiert werden kann. operator[]Ein Vektor ist in seiner Leistung nur mit einer Roh-Array-Indizierung vergleichbar, da der gesamte Operator inline und somit vollständig aus dem kompilierten Code entfernt werden kann. C # und Java geben viele Garantien für die Ausgabe des Compilers. Wenn ich eine Klasse in C # definiere, dann wird diese Klasse existiert in der Montage des resultierend. Auch wenn ich es nie benutze. Auch wenn alle Aufrufe seiner Mitgliedsfunktionen inline sein könnten. Die Klasse muss da sein, damit die Reflexion sie finden kann. Ein Teil davon wird durch das Kompilieren von C # zu Bytecode erleichtert, was bedeutet, dass der JIT-Compiler dies kannEntfernen Sie Klassendefinitionen und Inline-Funktionen, wenn dies gefällt, auch wenn der ursprüngliche C # -Compiler dies nicht kann. In C ++ haben Sie nur einen Compiler und dieser muss effizienten Code ausgeben. Wenn Sie die Metadaten einer ausführbaren C ++ - Datei überprüfen könnten, würden Sie erwarten, dass jede definierte Klasse angezeigt wird. Dies bedeutet, dass der Compiler alle definierten Klassen beibehalten muss, auch wenn sie nicht erforderlich sind.

  • Und dann gibt es Vorlagen. Vorlagen in C ++ sind nichts anderes als Generika in anderen Sprachen. Jede Vorlageninstanziierung erstellt einen neuen Typ. std::vector<int>ist eine völlig separate Klasse von std::vector<float>. Das summiert sich zu vielen verschiedenen Typen in einem gesamten Programm. Was soll unser Spiegelbild sehen? Die Vorlage std::vector ? Aber wie kann es sein, da dies ein Quellcode-Konstrukt ist, das zur Laufzeit keine Bedeutung hat? Es müsste die getrennten Klassen std::vector<int>und sehen std::vector<float>. Und std::vector<int>::iteratorund das std::vector<float>::iteratorgleiche fürconst_iteratorund so weiter. Und sobald Sie mit der Metaprogrammierung von Vorlagen beginnen, werden Sie schnell Hunderte von Vorlagen instanziieren, die alle vom Compiler eingebunden und wieder entfernt werden. Sie haben keine Bedeutung, außer als Teil eines Metaprogramms zur Kompilierungszeit. Sollten all diese Hunderte von Klassen für die Reflexion sichtbar sein? Sie müssten es tun, denn sonst wäre unser Nachdenken nutzlos, wenn es nicht einmal garantiert, dass die von mir definierten Klassen tatsächlich vorhanden sind . Ein Nebenproblem ist, dass die Vorlagenklasse erst existiert, wenn sie instanziiert wird. Stellen Sie sich ein Programm vor, das verwendet std::vector<int>. Sollte unser Reflexionssystem sehen können std::vector<int>::iterator? Einerseits würde man das sicherlich erwarten. Es ist eine wichtige Klasse, und es ist definiert in Bezug auf std::vector<int>, was tutexistieren in den Metadaten. Wenn das Programm diese Iterator-Klassenvorlage jedoch nie tatsächlich verwendet , wurde ihr Typ niemals instanziiert, sodass der Compiler die Klasse überhaupt nicht generiert hat. Und es ist zu spät, um es zur Laufzeit zu erstellen, da es Zugriff auf den Quellcode erfordert.

  • Und schließlich ist die Reflexion in C ++ nicht ganz so wichtig wie in C #. Der Grund ist wieder die Template-Metaprogrammierung. Es kann nicht alles lösen, aber in vielen Fällen, in denen Sie sonst auf Reflexion zurückgreifen würden, ist es möglich, ein Metaprogramm zu schreiben, das zur Kompilierungszeit dasselbe tut. boost::type_traitsist ein einfaches Beispiel. Sie möchten etwas über Typ wissen T? Überprüfen Sie seine type_traits. In C # müssten Sie nach dem Typ mit Reflexion herumfischen. Reflexion wäre für einige Dinge immer noch nützlich (die Hauptanwendung, die ich sehen kann, die Metaprogrammierung nicht einfach ersetzen kann, ist für automatisch generierten Serialisierungscode), aber sie würde einige erhebliche Kosten für C ++ verursachen und ist einfach nicht so oft erforderlich wie sie ist in anderen Sprachen.

Bearbeiten: Als Antwort auf Kommentare:

cdleary: Ja, Debug-Symbole tun etwas Ähnliches, indem sie Metadaten zu den in der ausführbaren Datei verwendeten Typen speichern. Sie leiden aber auch unter den von mir beschriebenen Problemen. Wenn Sie jemals versucht haben, einen Release-Build zu debuggen, wissen Sie, was ich meine. Es gibt große logische Lücken, in denen Sie eine Klasse im Quellcode erstellt haben, die im endgültigen Code nicht mehr berücksichtigt wurde. Wenn Sie Reflektion für etwas Nützliches verwenden möchten, muss es zuverlässiger und konsistenter sein. So wie es ist, würden Typen fast jedes Mal verschwinden und verschwinden, wenn Sie kompilieren. Sie ändern ein kleines Detail, und der Compiler entscheidet sich als Antwort dafür, zu ändern, welche Typen inline werden und welche nicht. Wie extrahieren Sie etwas Nützliches daraus, wenn Sie ' Ist nicht einmal garantiert, dass die relevantesten Typen in Ihren Metadaten dargestellt werden? Der Typ, nach dem Sie gesucht haben, war möglicherweise im letzten Build vorhanden, aber jetzt ist er weg. Und morgen wird jemand eine kleine unschuldige Änderung in eine kleine unschuldige Funktion einchecken, wodurch der Typ gerade so groß wird, dass er nicht vollständig inline wird, sodass er wieder zurück ist. Das ist immer noch nützlich für Debug-Symbole, aber nicht viel mehr. Ich würde es hassen, unter diesen Bedingungen Serialisierungscode für eine Klasse zu generieren. aber nicht viel mehr als das. Ich würde es hassen, unter diesen Bedingungen Serialisierungscode für eine Klasse zu generieren. aber nicht viel mehr als das. Ich würde es hassen, unter diesen Bedingungen Serialisierungscode für eine Klasse zu generieren.

Evan Teran: Natürlich könnten diese Probleme gelöst werden. Aber das fällt auf meinen ersten Punkt zurück. Es würde viel Arbeit kosten, und das C ++ - Komitee hat viele Dinge, die es für wichtiger hält. Ist der Vorteil einer eingeschränkten Reflexion (und dies wäre begrenzt) in C ++ wirklich groß genug, um eine Fokussierung auf Kosten anderer Funktionen zu rechtfertigen? Gibt es wirklich einen großen Vorteil beim Hinzufügen von Funktionen zur Kernsprache, die bereits (meistens) über Bibliotheken und Präprozessoren wie QTs möglich sind? Vielleicht, aber der Bedarf ist viel weniger dringend als wenn solche Bibliotheken nicht existieren würden. Für Ihre spezifischen Vorschläge glaube ich jedoch, dass das Nichtzulassen auf Vorlagen es völlig nutzlos machen würde. Sie können beispielsweise keine Reflektion für die Standardbibliothek verwenden. Was für eine Art von Reflexion würde das nicht?std::vector? Vorlagen sind ein großer Teil von C ++. Eine Funktion, die bei Vorlagen nicht funktioniert, ist grundsätzlich nutzlos.

Aber Sie haben Recht, es könnte eine Form der Reflexion implementiert werden. Aber es wäre eine große Änderung in der Sprache. Typen sind derzeit ausschließlich ein Konstrukt zur Kompilierungszeit. Sie existieren zum Nutzen des Compilers und sonst nichts. Sobald der Code kompiliert wurde, gibt es keine Klassen mehr. Wenn Sie sich strecken, könnten Sie argumentieren, dass es noch Funktionen gibt, aber eigentlich gibt es nur eine Reihe von Sprungassembler-Anweisungen und viele Stack-Push / Pops. Beim Hinzufügen solcher Metadaten ist nicht viel zu tun.

Aber wie gesagt, es gibt einen Vorschlag für Änderungen am Kompilierungsmodell, das Hinzufügen eigenständiger Module, das Speichern von Metadaten für ausgewählte Typen und das Ermöglichen, dass andere Module auf sie verweisen, ohne sich mit #includes herumschlagen zu müssen . Das ist ein guter Anfang, und um ehrlich zu sein, bin ich überrascht, dass das Standardkomitee den Vorschlag nicht einfach als zu große Änderung abgelehnt hat. Also vielleicht in 5-10 Jahren? :) :)


2
Müssen die meisten dieser Probleme nicht bereits durch Debug-Symbole gelöst werden? Nicht, dass es performant wäre (aufgrund des von Ihnen erwähnten Inlining und der Optimierung), aber Sie könnten die Möglichkeit der Reflexion berücksichtigen, indem Sie die Debug-Symbole ausführen.
CDLeary

2
Noch etwas zu Ihrem ersten Punkt: Soweit ich weiß, hat niemand versucht, einer C ++ - Implementierung Reflexion hinzuzufügen. Es gibt keine guten Erfahrungen damit. Der Ausschuss wird wahrscheinlich zögern, die Führung zu übernehmen, insbesondere nach exportund vector<bool>.
David Thornley

18
Ich bin damit einverstanden, dass C ++ keine Laufzeitreflexion haben sollte. Die Kompilierungszeitreflexion weist jedoch nur wenige der oben genannten Probleme auf und kann verwendet werden, wenn jemand die Laufzeitreflexion für bestimmte Klassen erstellt, wenn er dies wünscht. Auf den Typ, den Namen und die Funktionen der n-ten Methode und des n-ten übergeordneten Elements einer Klasse über eine Vorlage zugreifen können? Und die Anzahl solcher zur Kompilierungszeit erhalten? Würde CRTP-basierte automatische Reflexion machbar machen, während niemand für das bezahlt, was er nicht verwendet.
Yakk - Adam Nevraumont

15
Ihr dritter Punkt ist in vielerlei Hinsicht der wichtigste: C ++ soll zum Schreiben von eigenständigem Code auf Plattformen geeignet sein, auf denen Speicher Geld kostet. Wenn durch das Eliminieren von nicht verwendetem Code ein Programm in einen Mikrocontroller passt, der 2,00 USD kostet, und nicht in einen, der 2,50 USD kostet, und wenn der Code in 1.000.000 Einheiten ausgeführt wird, können durch das Eliminieren dieses Codes 500.000 USD eingespart werden. Ohne Reflexion kann die statische Analyse häufig 90% des nicht erreichbaren Codes identifizieren. Wenn Reflexion erlaubt ist, muss alles, was über Reflexion erreicht werden kann, als erreichbar angesehen werden, auch wenn 90% davon nicht erreichbar sind.
Supercat

2
Es gibt definitiv etwas, das vom Komitee leicht verbessert werden kann. Es heißt schließlich Schwarz auf Weiß, dass typeinfodie name()Funktion den vom Programmierer eingegebenen Namen zurückgeben MUSS und nicht etwas Undefiniertes. Und geben Sie uns auch einen Stringifizierer für Enumeratoren. Dies ist tatsächlich entscheidend für die Serialisierung / Deserialisierung, die Herstellung von Fabriken usw.
v.oddou

38

Für die Reflexion müssen einige Metadaten zu Typen an einem Ort gespeichert werden, der abgefragt werden kann. Da C ++ zu nativem Maschinencode kompiliert wird und aufgrund der Optimierung starke Änderungen erfährt, geht die Ansicht der Anwendung auf hoher Ebene beim Kompilieren so gut wie verloren. Daher ist es nicht möglich, sie zur Laufzeit abzufragen. Java und .NET verwenden eine sehr übergeordnete Darstellung im Binärcode für virtuelle Maschinen, die diese Reflexionsebene ermöglicht. In einigen C ++ - Implementierungen gibt es jedoch sogenannte RTTI (Run Time Type Information), die als abgespeckte Version der Reflexion betrachtet werden können.


15
RTTI ist im C ++ - Standard.
Daniel Earwicker

1
Aber nicht alle C ++ - Implementierungen sind Standard. Ich habe Implementierungen gesehen, die RTTI nicht unterstützen.
Mehrdad Afshari

3
Die meisten Implementierungen, die RTTI unterstützen, unterstützen auch das Deaktivieren über Compileroptionen.
Michael Kohne

21

Alle Sprachen sollten nicht versuchen, alle Funktionen jeder anderen Sprache zu integrieren.

C ++ ist im Wesentlichen ein sehr, sehr ausgefeilter Makro-Assembler. Es ist KEINE (im traditionellen Sinne) Hochsprache wie C #, Java, Objective-C, Smalltalk usw.

Es ist gut, verschiedene Werkzeuge für verschiedene Jobs zu haben. Wenn wir nur Hämmer haben, werden alle Dinge wie Nägel usw. aussehen. Skriptsprachen sind für einige Jobs nützlich, und reflektierende OO-Sprachen (Java, Obj-C, C #) sind für eine andere Klasse von Jobs nützlich und super -effiziente Bare-Bones-Sprachen in der Nähe der Maschine sind nützlich für eine weitere Klasse von Jobs (C ++, C, Assembler).

C ++ leistet einen erstaunlichen Beitrag zur Erweiterung der Assembler-Technologie auf ein unglaubliches Maß an Komplexitätsmanagement und Abstraktionen, um das Programmieren größerer, komplexerer Aufgaben für den Menschen erheblich zu ermöglichen. Es ist jedoch nicht unbedingt eine Sprache, die am besten für diejenigen geeignet ist, die sich ihrem Problem aus einer streng hochrangigen Perspektive nähern (Lisp, Smalltalk, Java, C #). Wenn Sie eine Sprache mit diesen Funktionen benötigen, um eine Lösung für Ihre Probleme zu implementieren, dann danken Sie denen, die solche Sprachen erstellt haben, damit wir sie alle verwenden können!

C ++ ist jedoch für diejenigen gedacht, die aus irgendeinem Grund eine starke Korrelation zwischen ihrem Code und dem Betrieb des zugrunde liegenden Computers benötigen. Unabhängig von der Effizienz, der Programmierung von Gerätetreibern oder der Interaktion mit den untergeordneten Betriebssystemdiensten oder was auch immer, C ++ ist für diese Aufgaben besser geeignet.

C #, Java und Objective-C erfordern alle ein viel größeres und umfangreicheres Laufzeitsystem, um ihre Ausführung zu unterstützen. Diese Laufzeit muss an das betreffende System geliefert werden - vorinstalliert, um den Betrieb Ihrer Software zu unterstützen. Und diese Schicht muss für verschiedene Zielsysteme beibehalten werden, die von EINIGER ANDERER SPRACHE angepasst wurden, damit sie auf dieser Plattform funktioniert. Und diese mittlere Schicht - diese adaptive Schicht zwischen dem Host-Betriebssystem und Ihrem Code - die Laufzeit - wird fast immer in einer Sprache wie C oder C ++ geschrieben, in der die Effizienz an erster Stelle steht und in der das genaue Verständnis der genauen Interaktion zwischen Software und Hardware gut sein kann verstanden und auf maximale Verstärkung manipuliert.

Ich liebe Smalltalk, Objective-C und ein reichhaltiges Laufzeitsystem mit Reflexion, Metadaten, Speicherbereinigung usw. Es kann erstaunlicher Code geschrieben werden, um diese Funktionen zu nutzen! Aber das ist einfach eine höhere Schicht auf dem Stapel, eine Schicht, die auf niedrigeren Schichten ruhen muss, die letztendlich selbst auf dem Betriebssystem und der Hardware sitzen muss. Und wir werden immer eine Sprache brauchen, die am besten zum Erstellen dieser Ebene geeignet ist: C ++ / C / Assembler.

Nachtrag: C ++ 11/14 erweitert die C ++ - Fähigkeit zur Unterstützung übergeordneter Abstraktionen und Systeme weiter. Threading, Synchronisation, präzise Speichermodelle und präzisere abstrakte Maschinendefinitionen ermöglichen es C ++ - Entwicklern, viele der Abstraktionen auf hoher Ebene zu erzielen, über die einige dieser nur auf hoher Ebene verwendeten Sprachen exklusive Domänen verfügten, während sie weiterhin nahezu Metallleistung und hervorragende Vorhersagbarkeit (dh minimale Laufzeitsubsysteme). Möglicherweise werden Reflexionsfunktionen in einer zukünftigen Version von C ++ für diejenigen, die dies wünschen, selektiv aktiviert - oder eine Bibliothek bietet solche Laufzeitdienste an (möglicherweise gibt es jetzt einen oder die Anfänge eines Boost-Dienstes?).


Ihr Punkt bezüglich der Laufzeit einer Sprache, die in einer anderen Sprache kompiliert werden muss, trifft im Fall von Objective-C nicht zu, da die Laufzeit in C geschrieben ist (von dem Objective-C eine Obermenge ist).
Richard J. Ross III

Das ist eine Unterscheidung ohne Unterschied. Welchen Unterschied macht es, wenn das von Objective-C verwendete Laufzeitsubsystem letztendlich nicht in Objective-C, sondern in C geschrieben ist?
Mordachai

3
Es tut mir Leid; Aber solange Sie es richtig verknüpfen, können Sie ein Objective-C-Programm in C kompilieren . Tatsächlich habe ich es hier gemacht: stackoverflow.com/a/10290255/427309 . Ihre gesamte obige Aussage ist falsch. Die Laufzeit ist über C vollständig zugänglich und eines der Dinge, die sie zu einer so mächtigen dynamischen Sprache machen.
Richard J. Ross III

1
Die "C-Laufzeit" ist nur eine dynamische Bibliothek, die den Code für die C-Standardbibliothek enthält. Gleiches gilt für die "C ++ - Laufzeit". Es unterscheidet sich erheblich von einem Laufzeitsystem wie dem von Objective-C. Auch ... während Sie vermutlich die Objective-C-Laufzeit in C technisch verwenden könnten, ist dies immer noch nur ein C-Programm, das die Objective-C-Laufzeit verwendet - Sie können kein tatsächliches Objective-C-Programm in C kompilieren.
celticminstrel

2
C ++ 11 mit einem Speichermodell + Atomics ähnelt eher einem tragbaren Assembler. Dies sind keine Dinge auf hoher Ebene, sondern Dinge auf niedriger Ebene, für die C ++ zuvor keine tragbare Unterstützung hatte. Die Menge an UB in C ++, wenn Sie etwas falsch machen, unterscheidet sich jedoch stark von VM-basierten Sprachen wie Java und auch von einer bestimmten Assemblersprache. Beispiel: Der signierte Überlauf ist in C ++ - Quellen vollständig UB und der Compiler kann basierend auf dieser Tatsache optimieren, selbst wenn er beispielsweise für x86 kompiliert wird. In asm wird er jedoch auf fast allen Plattformen nur umbrochen. Modernes C ++ ist sehr weit von einer portablen Assemblersprache entfernt.
Peter Cordes

11

Wenn Sie die Entwurfsentscheidungen für C ++ wirklich verstehen möchten, finden Sie eine Kopie des Referenzhandbuchs zu The Annotated C ++ von Ellis und Stroustrup. Es ist NICHT auf dem neuesten Stand des Standards, aber es geht durch den ursprünglichen Standard und erklärt, wie die Dinge funktionieren und oft, wie sie auf diese Weise entstanden sind.


6
Auch Design und Evolution von C ++ von Stroustrup
James Hopkin

9

Bei der Reflexion für Sprachen, in denen dies der Fall ist, geht es darum, wie viel des Quellcodes der Compiler in Ihrem Objektcode belassen möchte, um die Reflexion zu ermöglichen, und wie viel Analysemaschinerie zur Interpretation dieser reflektierten Informationen zur Verfügung steht. Wenn der Compiler nicht den gesamten Quellcode behält, ist die Fähigkeit der Reflection, die verfügbaren Fakten zum Quellcode zu analysieren, eingeschränkt.

Der C ++ - Compiler behält nichts in der Nähe (ignoriert RTTI), sodass Sie keine Reflexion in der Sprache erhalten. (Java- und C # -Compiler behalten nur Klassen-, Methodennamen und Rückgabetypen bei, sodass Sie ein wenig Reflexionsdaten erhalten, aber keine Ausdrücke oder Programmstrukturen überprüfen können, und das bedeutet, dass selbst in diesen "reflexionsfähigen" Sprachen die Informationen, die Sie erhalten können, sind ziemlich spärlich und folglich können Sie wirklich nicht viel analysieren.

Aber Sie können Schritt außerhalb der Sprache und voller Reflexion Fähigkeiten erhalten. Die Antwort auf eine andere Stapelüberlaufdiskussion zur Reflexion in C diskutiert dies.


7

Reflexion kann und wurde bereits in c ++ implementiert.

Es ist keine native C ++ - Funktion, da es hohe Kosten (Speicher und Geschwindigkeit) verursacht, die nicht standardmäßig von der Sprache festgelegt werden sollten - die Sprache ist auf "maximale Leistung standardmäßig" ausgerichtet.

Da Sie nicht für das bezahlen sollten, was Sie nicht benötigen, und wie Sie selbst sagen, dass es in Editoren mehr benötigt wird als in anderen Anwendungen, sollte es nur dort implementiert werden, wo Sie es benötigen, und nicht zum gesamten Code "gezwungen" werden ( Sie müssen nicht über alle Daten nachdenken, mit denen Sie in einem Editor oder einer ähnlichen Anwendung arbeiten.


3
und Sie versenden keine Symbole, da dies Ihren Kunden / Mitbewerbern ermöglichen würde, Ihren Code einzusehen ... dies wird oft als schlechte Sache angesehen.
Gbjbaanb

Du hast recht, ich habe nicht einmal über das Problem der Code-Exposition
nachgedacht

6

Der Grund, warum C ++ keine Reflexion aufweist, besteht darin, dass die Compiler den Objektdateien Symbolinformationen hinzufügen müssen, z. B. welche Elemente ein Klassentyp hat, Informationen zu den Elementen, zu den Funktionen und allem. Dies würde im Wesentlichen Include-Dateien unbrauchbar machen, da durch Deklarationen gelieferte Informationen dann aus diesen Objektdateien (dann Modulen) gelesen würden. In C ++ kann eine Typdefinition in einem Programm mehrfach vorkommen, indem die entsprechenden Header eingeschlossen werden (vorausgesetzt, alle diese Definitionen sind identisch). Daher müsste entschieden werden, wo die Informationen zu diesem Typ abgelegt werden sollen, um nur einen zu nennen Komplikation hier. Die aggressive Optimierung durch einen C ++ - Compiler, der Dutzende von Instanziierungen von Klassenvorlagen optimieren kann, ist eine weitere Stärke. Es ist möglich, aber da C ++ mit C kompatibel ist,


1
Ich verstehe nicht, wie stark die aggressive Optimierung des Compilers ist. Können Sie das näher erläutern? Wenn der Linker doppelte Inline-Funktionsdefinitionen entfernen kann, was ist das Problem mit doppelten Reflexionsinformationen? Werden den Objektdateien für Debugger ohnehin keine Symbolinformationen hinzugefügt?
Rob Kennedy

1
Das Problem ist, dass Ihre Reflexionsinformationen möglicherweise ungültig sind. Wenn der Compiler 80% Ihrer Klassendefinitionen eliminiert, was werden Ihre Reflexionsmetadaten sagen? In C # und Java garantiert die Sprache, dass eine Klasse definiert bleibt, wenn Sie sie definieren. Mit C ++ kann der Compiler es optimieren.
Jalf

1
@Rob, die Optimierungen sind ein weiterer Punkt, der nicht an die Komplikation mehrerer Klassen gebunden ist. Siehe @ jalfs Kommentar (und seine Antwort) für das, was ich meinte.
Johannes Schaub - Litb

4
Wenn ich das Reflektieren von <T> instanziiere, werfen Sie keine Informationen von T weg. Dies scheint kein unlösbares Problem zu sein.
Joseph Garvin

3

Es gibt unzählige Fälle für die Verwendung von Reflection in C ++, die mit Konstrukten zur Kompilierungszeit wie der Metaprogrammierung von Vorlagen nicht angemessen behandelt werden können.

N3340 schlägt umfangreiche Zeiger vor, um die Reflexion in C ++ einzuführen. Unter anderem wird das Problem behoben, dass eine Funktion nur dann bezahlt wird, wenn Sie sie verwenden.


2

Laut Alistair Cockburn kann die Subtypisierung in einer reflektierenden Umgebung nicht garantiert werden .

Reflexion ist für latente Typisierungssysteme relevanter. In C ++ wissen Sie, welchen Typ Sie haben und was Sie damit tun können.


Allgemeiner gesagt ermöglicht die Möglichkeit, das Vorhandensein eines Features zu überprüfen, das nicht vorhanden ist, ohne undefiniertes Verhalten einzuführen, dass das Hinzufügen dieses Features zu einer späteren Version einer Klasse das genau definierte Verhalten bereits vorhandener Programme ändert Infolgedessen ist es unmöglich zu garantieren, dass das Hinzufügen dieser Funktion nichts "kaputt macht".
Superkatze

2

Reflexion kann optional sein, wie eine Präprozessor-Direktive. Etwas wie

#pragma enable reflection

Auf diese Weise können wir das Beste aus beiden Welten haben, ohne dass diese Pragma-Bibliotheken ohne Reflexion erstellt würden (ohne Overhead, wie besprochen), und es wäre Sache des einzelnen Entwicklers, ob er Geschwindigkeit oder Benutzerfreundlichkeit wünscht.


2

Wenn C ++ haben könnte:

  • Klassenmitgliedsdaten für Variablennamen, Variablentypen und die const Modifikator
  • ein Funktionsargument-Iterator (nur Position anstelle von Name)
  • Klassenmitgliedsdaten für Funktionsnamen, Rückgabetyp und const Modifikator
  • Liste der übergeordneten Klassen (in derselben Reihenfolge wie definiert)
  • Daten für Vorlagenmitglieder und übergeordnete Klassen; die erweiterte Vorlage (dh der tatsächliche Typ wäre für die Reflection-API verfügbar und nicht die "Vorlageninformationen für den Weg dorthin")

Dies würde ausreichen, um sehr einfach zu verwendende Bibliotheken im Kern der typenlosen Datenverarbeitung zu erstellen, die in den heutigen Web- und Datenbankanwendungen (allen Ormen, Messaging-Mechanismen, XML / JSON-Parsern, Datenserialisierung usw.) so weit verbreitet ist.

Zum Beispiel die vom Q_PROPERTYMakro unterstützten grundlegenden Informationen (Teil von Qt Framework) http://qt.nokia.com/doc/4.5/properties.html wären die auf Klassenmethoden und e) erweitert wurden, für C ++ und C außerordentlich vorteilhaft die Software-Community im Allgemeinen.

Sicherlich würde die Reflexion, auf die ich mich beziehe, nicht die semantische Bedeutung oder komplexere Probleme (wie Kommentare, Quellcode-Zeilennummern, Datenflussanalyse usw.) abdecken - aber ich denke auch nicht, dass diese Teil eines Sprachstandards sein müssen.


@Vlad: Ja, wenn man der Sprache Funktionen hinzufügt, die die Reflexion unterstützen, erhält man Reflexion in der Sprache. Dies wird wahrscheinlich nur passieren, wenn das Sprachkomitee dies beschließt, und ich denke, dass dies nicht ab 2011 der Fall ist, und ich bezweifle, dass es vor 2020 n. Chr. Einen weiteren C ++ - Standard geben wird. Also, schöner Gedanke. Wenn Sie in der Zwischenzeit Fortschritte erzielen möchten, müssen Sie wahrscheinlich C ++ verlassen.
Ira Baxter


0

Die Reflexion in C ++ ist meiner Meinung nach von entscheidender Bedeutung, wenn C ++ als Sprache für den Datenbankzugriff, die Behandlung von Websitzungen / http und die GUI-Entwicklung verwendet werden soll. Die mangelnde Reflexion verhindert, dass ORMs (wie Hibernate oder LINQ), XML- und JSON-Parser Klassen instanziieren, Datenserialisierung und viele andere Thigns (bei denen zunächst typenlose Daten zum Erstellen einer Instanz einer Klasse verwendet werden müssen).

Ein Kompilierungszeitschalter, der einem Softwareentwickler während des Erstellungsprozesses zur Verfügung steht, kann verwendet werden, um dieses Problem zu beseitigen, dass Sie für das bezahlen, was Sie verwenden.

Wenn ein Firmwaredeveloper die Reflektion nicht benötigt, um Daten von einer seriellen Schnittstelle zu lesen, kann der Switch nicht verwendet werden. Aber als Datenbankentwickler, der weiterhin C ++ verwenden möchte, habe ich ständig einen schrecklichen, schwer zu pflegenden Code, der Daten zwischen Datenelementen und Datenbankkonstrukten abbildet.

Weder die Boost-Serialisierung noch andere Mechanismen lösen die Reflexion wirklich - dies muss vom Compiler durchgeführt werden - und sobald dies geschehen ist, wird C ++ erneut in Schulen unterrichtet und in Software verwendet, die sich mit Datenverarbeitung befasst

Für mich ist dieses Problem Nr. 1 (und naive Threading-Grundelemente sind Problem Nr. 2).


4
Wer hat gesagt, C ++ ist für DB - Zugang, Web - Session hnadling oder gui dev als eine Sprache verwendet werden? Es gibt viele weitaus bessere Sprachen für solche Dinge. Ein Schalter zur Kompilierungszeit löst das Problem nicht. Normalerweise wird die Entscheidung zum Aktivieren oder Deaktivieren der Reflexion nicht pro Datei getroffen. Es könnte funktionieren, wenn es für einzelne Typen aktiviert werden könnte. Wenn der Programmierer beim Definieren eines Typs ein Attribut oder ähnliches angeben kann, ob Reflexionsmetadaten für diesen Typ generiert werden sollen oder nicht. Aber ein globaler Schalter? Sie würden 90% der Sprache verkrüppeln, nur um 10% davon einfacher zu machen.
Jalf

Was sollte ich dann verwenden, wenn ich ein plattformübergreifendes Programm haben möchte und Zugriff auf eine GUI habe? Die unflexible Java-Schaukel? Die Fenster nur C #? Aber die Wahrheit sollte gesagt werden, und die Wahrheit ist, dass es viele Programme gibt, die in ausführbarem Code kompiliert sind und eine GUI-Schnittstelle und Zugriff auf Datenbanken bieten, also müssen sie eine Datenbank- und GUI-Unterstützung verwenden ... Und sie sind es nicht. t mit QT. (Es sollte MT (Monster Toolkit) heißen.)
heißen

1
@ Coyote21: C # ist seit Jahren nicht mehr nur für Windows. (Obwohl ich kein Fan von Mono bin, funktioniert es für die meisten Dinge gut genug.) Und Swing ist nicht das einzige GUI-Toolkit für Java. Um ehrlich zu sein, wäre entweder eine bessere Wahl, wenn Sie plattformübergreifend sein möchten. C ++ wird hier oder da so ziemlich immer plattformspezifische Teile haben, wenn Sie etwas tun, das nicht trivial ist.
CHao

Es gibt keinen Grund, warum Sie Reflexion für ORM benötigen. All dies können Sie mit Vorlagen erreichen. Es gibt eine Reihe von Frameworks, die ORM für C ++ bereitstellen.
MrFox

0

Es ist im Grunde, weil es ein "optionales Extra" ist. Viele Leute wählen C ++ gegenüber Sprachen wie Java und C #, um mehr Kontrolle über die Compilerausgabe zu haben, z. B. ein kleineres und / oder schnelleres Programm.

Wenn Sie Reflexion hinzufügen möchten, stehen verschiedene Lösungen zur Verfügung .

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.