Wenn Sie in C #, C ++ und Java einen Konstruktor erstellen, der Parameter verwendet, wird der standardmäßige parameterlose Parameter entfernt. Ich habe diese Tatsache immer nur akzeptiert, aber jetzt frage ich mich warum.
Was ist der Grund für dieses Verhalten? Ist es nur eine "Sicherheitsmaßnahme / Vermutung", die besagt: "Wenn Sie einen eigenen Konstruktor erstellt haben, möchten Sie wahrscheinlich nicht, dass dieser implizite herumhängt"? Oder hat es einen technischen Grund, der es dem Compiler unmöglich macht, einen hinzuzufügen, nachdem Sie selbst einen Konstruktor erstellt haben?
c#
java
c++
default-constructor
Olagjo
quelle
quelle
Foo() = default;
, dass Sie die Standardeinstellung zurückerhalten möchten.Antworten:
Es gibt keinen Grund, warum der Compiler den Konstruktor nicht hinzufügen könnte, wenn Sie Ihren eigenen hinzugefügt hätten - der Compiler könnte so ziemlich alles tun, was er will! Sie müssen sich jedoch ansehen, was am sinnvollsten ist:
In jedem Fall können Sie also sehen, dass das Verhalten aktueller Compiler im Hinblick auf die Wahrung der wahrscheinlichen Absicht des Codes am sinnvollsten ist .
quelle
Es gibt sicherlich keinen technischen Grund , warum die Sprache hat diese Art und Weise zu gestalten.
Es gibt vier etwas realistische Optionen, die ich sehen kann:
Option 1 ist insofern etwas attraktiv, als je mehr ich codiere, desto seltener möchte ich wirklich einen parameterlosen Konstruktor. Eines Tages sollte ich zählen, wie oft ich tatsächlich einen Standardkonstruktor verwende ...
Option 2 Mir geht es gut.
Option 3 widerspricht für den Rest der Sprache dem Fluss von Java und C #. Es gibt nie etwas, das Sie explizit "entfernen", es sei denn, Sie zählen, um Dinge explizit privater zu machen, als dies in Java standardmäßig der Fall wäre.
Option 4 ist schrecklich - Sie möchten unbedingt die Konstruktion mit bestimmten Parametern erzwingen können. Was würde das
new FileStream()
überhaupt bedeuten?Also im Grunde, wenn Sie die Prämisse akzeptieren , dass ein Standard - Konstruktor Bereitstellung Sinn macht, glaube ich es sehr viel Sinn macht es zu unterdrücken, sobald Sie Ihren eigenen Konstruktor zur Verfügung stellen.
quelle
struct
s, zum Guten oder Schlechten.Bearbeiten. Während das, was ich in meiner ersten Antwort sage, gültig ist, ist dies der wahre Grund:
Am Anfang war C. C ist nicht objektorientiert (Sie können einen OO-Ansatz wählen, aber es hilft Ihnen nicht oder erzwingt nichts).
Dann gab es C With Classes, das später in C ++ umbenannt wurde. C ++ ist objektorientiert und fördert daher die Kapselung und stellt die Invariante eines Objekts sicher. Bei der Erstellung sowie zu Beginn und am Ende einer Methode befindet sich das Objekt in einem gültigen Zustand.
Damit können Sie natürlich erzwingen, dass eine Klasse immer einen Konstruktor haben muss, um sicherzustellen, dass sie in einem gültigen Zustand startet. Wenn der Konstruktor nichts tun muss, um dies sicherzustellen, dokumentiert der leere Konstruktor diese Tatsache .
Ein Ziel mit C ++ war es jedoch, mit C so kompatibel zu sein, dass so weit wie möglich alle gültigen C-Programme auch gültige C ++ - Programme waren (kein so aktives Ziel mehr, und die Entwicklung von C getrennt von C ++ bedeutet, dass es nicht mehr gilt ).
Ein Effekt davon war die Verdoppelung der Funktionalität zwischen
struct
undclass
. Die ersteren machen die Dinge auf die C-Art (standardmäßig alles öffentlich) und die letzteren machen die Dinge auf eine gute OO-Art (standardmäßig alles privat, der Entwickler macht aktiv öffentlich, was sie öffentlich wollen).Eine andere ist, dass, damit ein C
struct
, das keinen Konstruktor haben konnte, weil C keine Konstruktoren hat, in C ++ gültig sein musste, dies eine Bedeutung für die C ++ - Sichtweise haben musste. Obwohl es keinen Konstruktor gibt, der gegen die OO-Praxis verstößt, eine Invariante aktiv sicherzustellen, bedeutet C ++, dass es einen standardmäßigen parameterlosen Konstruktor gibt, der sich so verhält, als hätte er einen leeren Körper.Alle C
structs
waren jetzt gültige C ++structs
(was bedeutete, dass sie mit C ++ identisch waren,classes
wobei alles - Mitglieder und Vererbung - öffentlich) von außen so behandelt wurde, als hätte es einen einzigen, parameterlosen Konstruktor.Wenn Sie jedoch einen Konstruktor in ein
class
oderstruct
eingefügt haben, haben Sie die Dinge eher auf C ++ / OO-Weise als auf C-Weise ausgeführt, und es war kein Standardkonstruktor erforderlich.Da es als Abkürzung diente, wurde es weiterhin verwendet, auch wenn die Kompatibilität sonst nicht möglich war (es wurden andere C ++ - Funktionen verwendet, die nicht in C enthalten waren).
Als Java (in vielerlei Hinsicht auf C ++ basierend) und später C # (auf unterschiedliche Weise auf C ++ und Java basierend) auf den Markt kamen, behielten sie diesen Ansatz bei, wie es Codierer möglicherweise bereits gewohnt sind.
Stroustrup schreibt darüber in seiner Programmiersprache The C ++ und noch mehr, wobei er sich mehr auf das "Warum" der Sprache in The Design and Evolution of C ++ konzentriert .
=== Ursprüngliche Antwort ===
Nehmen wir an, das ist nicht passiert.
Angenommen, ich möchte keinen parameterlosen Konstruktor, weil ich meine Klasse ohne einen nicht in einen sinnvollen Zustand versetzen kann. In der Tat kann dies
struct
in C # passieren (aber wenn Sie in C # keine Nullen und Nullen sinnvoll verwenden können, verwendenstruct
Sie bestenfalls eine nicht öffentlich sichtbare Optimierung und haben ansonsten eine Konstruktionsfehler bei der Verwendungstruct
).Damit meine Klasse ihre Invarianten schützen kann, benötige ich ein spezielles
removeDefaultConstructor
Schlüsselwort. Zumindest müsste ich einen privaten parameterlosen Konstruktor erstellen, um sicherzustellen, dass kein aufrufender Code die Standardeinstellung aufruft.Was die Sprache noch komplizierter macht. Besser nicht.
Insgesamt ist es am besten, nicht daran zu denken, einen Konstruktor hinzuzufügen, um den Standard zu entfernen, sondern sich überhaupt keinen Konstruktor als syntaktischen Zucker für das Hinzufügen eines parameterlosen Konstruktors vorzustellen, der nichts tut.
quelle
Der standardmäßige, parameterlose Konstruktor wird hinzugefügt, wenn Sie selbst nichts tun, um die Kontrolle über die Objekterstellung zu übernehmen. Sobald Sie einen einzelnen Konstruktor erstellt haben, um die Kontrolle zu übernehmen, "zieht" sich der Compiler zurück und gibt Ihnen die volle Kontrolle.
Wenn dies nicht so wäre, müssten Sie den Standardkonstruktor explizit deaktivieren, wenn Objekte nur über einen Konstruktor mit Parametern konstruierbar sein sollen.
quelle
Es ist eine Komfortfunktion des Compilers. Wenn Sie einen Konstruktor mit Parametern definieren, aber keinen parameterlosen Konstruktor definieren, ist die Wahrscheinlichkeit, dass Sie keinen parameterlosen Konstruktor zulassen möchten, viel höher.
Dies ist bei vielen Objekten der Fall, deren Initialisierung mit einem leeren Konstruktor einfach keinen Sinn macht.
Andernfalls müssten Sie für jede Klasse, die Sie einschränken möchten, einen privaten parameterlosen Konstruktor deklarieren.
Meiner Meinung nach ist es kein guter Stil, einen parameterlosen Konstruktor für eine Klasse zuzulassen, für deren Funktion Parameter erforderlich sind.
quelle
Ich denke, die Frage sollte umgekehrt sein: Warum müssen Sie keinen Standardkonstruktor deklarieren, wenn Sie keine anderen Konstruktoren definiert haben?
Ein Konstruktor ist für nicht statische Klassen obligatorisch.
Wenn Sie also keine Konstruktoren definiert haben, ist der generierte Standardkonstruktor nur eine praktische Funktion des C # -Compilers. Ohne einen Konstruktor wäre Ihre Klasse auch nicht gültig. Es ist also nichts Falsches daran, implizit einen Konstruktor zu generieren, der nichts tut. Es sieht auf jeden Fall sauberer aus, als überall leere Konstruktoren zu haben.
Wenn Sie bereits einen Konstruktor definiert haben, ist Ihre Klasse gültig. Warum sollte der Compiler also davon ausgehen, dass Sie einen Standardkonstruktor möchten? Was ist, wenn Sie keine wollen? Ein Attribut implementieren, um den Compiler anzuweisen, diesen Standardkonstruktor nicht zu generieren? Ich denke nicht, dass das eine gute Idee wäre.
quelle
Der Standardkonstruktor kann nur erstellt werden, wenn die Klasse keinen Konstruktor hat. Compiler sind so geschrieben, dass sie nur als Sicherungsmechanismus dienen.
Wenn Sie einen parametrisierten Konstruktor haben, möchten Sie möglicherweise nicht, dass ein Objekt mit dem Standardkonstruktor erstellt wird. Hätte der Compiler einen Standardkonstruktor bereitgestellt, hätten Sie einen Konstruktor ohne Argumente schreiben und privat machen müssen, um zu verhindern, dass Objekte ohne Argumente erstellt werden.
Außerdem besteht eine höhere Wahrscheinlichkeit, dass Sie das Deaktivieren oder "Privatisieren" des Standardkonstruktors vergessen und dadurch einen potenziellen Funktionsfehler verursachen, der schwer zu erkennen ist.
Und jetzt müssen Sie explizit einen Konstruktor ohne Argumente definieren, wenn ein Objekt entweder standardmäßig oder durch Übergabe von Parametern erstellt werden soll. Dies wird stark überprüft, und der Compiler beschwert sich anders, wodurch hier keine Lücke sichergestellt wird.
quelle
Prämisse
Dieses Verhalten kann als natürliche Erweiterung der Entscheidung für Klassen angesehen werden, einen standardmäßigen öffentlichen parameterlosen Konstruktor zu haben . Basierend auf der gestellten Frage nehmen wir diese Entscheidung als Voraussetzung und gehen davon aus, dass wir sie in diesem Fall nicht in Frage stellen.
Möglichkeiten zum Entfernen des Standardkonstruktors
Daraus folgt, dass es eine Möglichkeit geben muss, den standardmäßigen öffentlichen parameterlosen Konstruktor zu entfernen. Diese Entfernung kann auf folgende Weise erreicht werden:
Auswahl der besten Lösung
Jetzt fragen wir uns: Wenn es keinen parameterlosen Konstruktor gibt, durch welchen muss er ersetzt werden? und Unter welchen Szenarien möchten wir den standardmäßigen öffentlichen parameterlosen Konstruktor entfernen?
Die Dinge fangen an, sich zusammenzufügen. Erstens muss es entweder durch einen Konstruktor mit Parametern oder durch einen nicht öffentlichen Konstruktor ersetzt werden. Zweitens sind die Szenarien, unter denen Sie keinen parameterlosen Konstruktor benötigen, folgende:
Fazit
Da haben wir es - genau die zwei Möglichkeiten, mit denen C #, C ++ und Java das Entfernen des standardmäßigen öffentlichen parameterlosen Konstruktors ermöglichen.
quelle
= delete
zu diesem Zweck eingeführt.Ich denke, das wird vom Compiler erledigt. Wenn Sie die
.net
Assembly in öffnenILDASM
, wird der Standardkonstruktor angezeigt, auch wenn er nicht im Code enthalten ist. Wenn Sie einen parametrisierten Konstruktor definieren, wird der Standardkonstruktor nicht angezeigt.Wenn Sie die Klasse definieren (nicht statisch), stellt der Compiler diese Funktion bereit und denkt, dass Sie nur eine Instanz erstellen. Und wenn Sie möchten, dass eine bestimmte Operation ausgeführt wird, haben Sie sicherlich einen eigenen Konstruktor.
quelle
Wenn Sie keinen Konstruktor definieren, generiert der Compiler automatisch einen Konstruktor für Sie, der keine Argumente akzeptiert. Wenn Sie etwas mehr von einem Konstruktor wollen, überschreiben Sie es. Dies ist KEINE Funktionsüberlastung. Der einzige Konstruktor, den der Compiler jetzt sieht, ist Ihr Konstruktor, der ein Argument akzeptiert. Um diesem Problem entgegenzuwirken, können Sie einen Standardwert übergeben, wenn der Konstruktor ohne Wert übergeben wird.
quelle
Eine Klasse braucht einen Konstruktor. Es ist obligatorisch.
Ich werde Ihre Frage mit einem anderen beantworten, warum wollen wir immer einen standardmäßigen parameterlosen Konstruktor? Es gibt Fälle, in denen dies nicht erwünscht ist, sodass der Entwickler die Kontrolle hat, es nach Bedarf hinzuzufügen oder zu entfernen.
quelle