Kurze Frage: Aus gestalterischer Sicht gibt es in C ++ keine Basisklasse für alle Mutter, was normalerweise object
in anderen Sprachen der Fall ist.
c++
language-design
Slezica
quelle
quelle
typedef
s verwenden. Mit einer allgemeineren Klassenhierarchie können Sie einfachobject
oder verwendeniterator
.Antworten:
Die endgültige Entscheidung finden Sie in den FAQs von Stroustrup . Kurz gesagt, es vermittelt keine semantische Bedeutung. Es wird Kosten haben. Vorlagen sind für Container nützlicher.
quelle
Objects must be heap-allocated to be polymorphic
- Ich denke nicht, dass diese Aussage im Allgemeinen richtig ist. Sie können definitiv eine Instanz einer polymorphen Klasse auf dem Stapel erstellen und als Zeiger auf eine ihrer Basisklassen weitergeben, was zu einem polymorphen Verhalten führt.Foo
in einen Referenz-to-Bar
wennBar
nicht erben wirdFoo
, deterministisch eine Ausnahme auslöst. In C ++ könnte der Versuch, einen Zeiger auf Foo in einen Zeiger auf einen Balken umzuwandeln, einen Roboter rechtzeitig zurückschicken, um Sarah Connor zu töten.Lassen Sie uns zunächst darüber nachdenken, warum Sie überhaupt eine Basisklasse haben möchten. Ich kann mir ein paar verschiedene Gründe vorstellen:
Dies sind die beiden guten Gründe, warum Sprachen der Marken Smalltalk, Ruby und Objective-C Basisklassen haben (technisch gesehen hat Objective-C keine Basisklasse, aber in jeder Hinsicht).
Für # 1 wird die Notwendigkeit einer Basisklasse, die alle Objekte unter einer einzigen Schnittstelle vereint, durch die Aufnahme von Vorlagen in C ++ vermieden. Zum Beispiel:
ist unnötig, wenn Sie die Typintegrität durch parametrischen Polymorphismus vollständig aufrechterhalten können!
Während in Objective-C Speicherverwaltungsprozeduren Teil der Implementierung einer Klasse sind und von der Basisklasse geerbt werden, wird die Speicherverwaltung in C ++ eher durch Komposition als durch Vererbung durchgeführt. Sie können beispielsweise einen Smart Pointer Wrapper definieren, der die Referenzzählung für Objekte eines beliebigen Typs durchführt:
Anstatt Methoden für das Objekt selbst aufzurufen, würden Sie dann Methoden in seinem Wrapper aufrufen. Dies ermöglicht nicht nur eine allgemeinere Programmierung, sondern ermöglicht es Ihnen auch, Bedenken zu trennen (da Ihr Objekt im Idealfall mehr darüber nachdenken sollte, was es tun sollte, als darüber, wie sein Speicher in verschiedenen Situationen verwaltet werden sollte).
Schließlich in einer Sprache, die sowohl Grundelemente als auch tatsächliche Objekte wie C ++ enthält, die Vorteile einer Basisklasse (eine konsistente Schnittstelle für alle Wert) verloren, da Sie dann bestimmte Werte haben, die dieser Schnittstelle nicht entsprechen können. Um Primitive in einer solchen Situation zu verwenden, müssen Sie sie in Objekte heben (wenn Ihr Compiler dies nicht automatisch tut). Dies verursacht viele Komplikationen.
Die kurze Antwort auf Ihre Frage: C ++ hat keine Basisklasse, da dies aufgrund des parametrischen Polymorphismus durch Vorlagen nicht erforderlich ist.
quelle
object
(System.Object
), aber nicht sein müssen. Für den Compilerint
undSystem.Int32
sind Aliase und können austauschbar verwendet werden; Die Laufzeit übernimmt das Boxen bei Bedarf.std::shared_ptr
, der stattdessen verwendet werden sollte.Das vorherrschende Paradigma für C ++ - Variablen ist Pass-by-Value, nicht Pass-by-Ref. Erzwingen, dass alles von einer Wurzel abgeleitet wird
Object
würde das Übergeben als Wert ipse facto zu einem Fehler machen.(Weil das Akzeptieren eines Objekts nach Wert als Parameter es per Definition in Scheiben schneiden und seine Seele entfernen würde).
Das ist nicht erwünscht. In C ++ überlegen Sie, ob Sie eine Wert- oder Referenzsemantik wünschen, und haben die Wahl. Dies ist eine große Sache im Performance Computing.
quelle
Object
wären relativ gering.Das Problem ist, dass es in C ++ einen solchen Typ gibt! Es ist
void
. :-) Jeder Zeiger kann sicher implizit auf geworfen werdenvoid *
, einschließlich Zeiger auf Basistypen, Klassen ohne virtuelle Tabelle und Klassen mit virtueller Tabelle.Da es mit all diesen Objektkategorien kompatibel sein sollte,
void
kann es selbst keine virtuellen Methoden enthalten. Ohne virtuelle Funktionen und RTTI können keine nützlichen Informationen zum Typ abgerufen werdenvoid
(sie stimmen mit JEDEM Typ überein, können also nur Dinge sagen, die für JEDEN Typ zutreffen), aber virtuelle Funktionen und RTTI würden einfache Typen sehr unwirksam machen und C ++ daran hindern, zu sein Eine Sprache, die für Low-Level-Programmierung mit direktem Speicherzugriff usw. geeignet ist.Es gibt also einen solchen Typ. Es bietet nur eine sehr minimalistische (tatsächlich leere) Oberfläche, da die Sprache nur ein niedriges Niveau aufweist. :-)
quelle
void
.void
, wird sie nicht kompiliert und Sie erhalten diesen Fehler . In Java könnten Sie eine Variable vom Typ habenObject
und es würde funktionieren. Das ist der Unterschied zwischenvoid
und einem "echten" Typ. Vielleicht ist es wahr, dass diesvoid
der Basistyp für alles ist, aber da es keine Konstruktoren, Methoden oder Felder enthält, gibt es keine Möglichkeit zu sagen, ob es da ist oder nicht. Diese Behauptung kann nicht bewiesen oder widerlegt werden.void
ein Typ ist (und eine etwas clevere Verwendung entdeckt hat? :
), aber es ist noch weit davon entfernt, eine universelle Basisklasse zu sein. Zum einen ist es "ein unvollständiger Typ, der nicht vervollständigt werden kann", und zum anderen gibt es keinenvoid&
Typ.C ++ ist eine stark typisierte Sprache. Es ist jedoch verwunderlich, dass es im Rahmen der Vorlagenspezialisierung keinen universellen Objekttyp gibt.
Nehmen Sie zum Beispiel das Muster
was als instanziiert werden kann
Nehmen wir nun an, wir wollen dasselbe für eine bestimmte Funktion. Mögen
mit der spezialisierten Instanziierung
Aber leider gibt es, obwohl Klasse T vor der Spezialisierung für jeden Typ (Klasse oder nicht) stehen kann, kein Äquivalent
auto fallback
(ich verwende diese Syntax als die offensichtlichste generische Nicht-Typ-Syntax in diesem Zusammenhang), das für jeden stehen könnte Nicht typisiertes Vorlagenargument vor der Spezialisierung.Im Allgemeinen wird dieses Muster also nicht von Typvorlagenvorlagenargumenten auf Nicht-Typvorlagenvorlagenargumente übertragen.
Wie bei vielen Ecken in der C ++ - Sprache lautet die Antwort wahrscheinlich "kein Ausschussmitglied hat daran gedacht".
quelle
ReturnType fallback(ArgTypes...)
funktionieren würde, wäre es schlechtes Design.template <class T, auto fallback> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...), ReturnType(*fallback)(ArgTypes...)> ...
tut, was Sie wollen und bedeutet, dass die VorlagenparameterHook
von konsistenter Art sindC ++ wurde ursprünglich "C mit Klassen" genannt. Es ist eine Weiterentwicklung der C-Sprache, im Gegensatz zu einigen anderen moderneren Dingen wie C #. Und Sie können C ++ nicht als Sprache sehen, sondern als Grundlage von Sprachen (Ja, ich erinnere mich an das Scott Meyers-Buch Effective C ++).
C selbst ist eine Mischung aus Sprachen, der Programmiersprache C und ihrem Präprozessor.
C ++ fügt eine weitere Mischung hinzu:
der Klassen- / Objektansatz
Vorlagen
die STL
Ich persönlich mag einige Sachen nicht, die direkt von C nach C ++ kommen. Ein Beispiel ist die Aufzählungsfunktion. Die Art und Weise, wie C # es dem Entwickler ermöglicht, es zu verwenden, ist viel besser: Es begrenzt die Aufzählung in seinem eigenen Bereich, hat eine Count-Eigenschaft und ist leicht iterierbar.
Da C ++ mit C nachträglich kompatibel sein wollte, war der Designer sehr tolerant, die C-Sprache in C ++ vollständig eingeben zu lassen (es gibt einige subtile Unterschiede, aber ich erinnere mich an nichts, was Sie mit einem C-Compiler tun könnten, den Sie verwenden konnte nicht mit einem C ++ - Compiler tun).
quelle