En C #, C++ et Java, lorsque vous créez un constructeur en prenant des paramètres, celui sans paramètre par défaut disparaît. Je viens toujours d'accepter ce fait, mais maintenant je me demande pourquoi.
Quelle est la raison de ce comportement? S'agit-il simplement d'une "mesure de sécurité/devinette" disant "Si vous avez créé votre propre constructeur, vous n'êtes probablement pas intéressé par celui-ci implicite"? .__ cela empêche le compilateur d’en ajouter un une fois que vous avez créé vous-même un constructeur?
Il n'y a aucune raison pour que le compilateur ne puisse pas ajouter le constructeur si vous avez ajouté le vôtre - le compilateur pourrait faire à peu près tout ce qu'il veut! Cependant, vous devez regarder ce qui est le plus logique:
Ainsi, dans chaque cas, vous pouvez voir que le comportement des compilateurs actuels est le plus logique en termes de préservation de l'intention probable du code.
Il n'y a certainement aucune raison technique pour laquelle le langage a soit conçu de cette façon.
Il y a quatre options assez réalistes que je peux voir:
L'option 1 est un peu attrayante, car plus je code, moins je vraiment veux un constructeur sans paramètre. Un jour, je devrais compter combien de fois je (réellement} _ finis par utiliser un constructeur par défaut ...
Option 2 je vais bien avec.
L'option 3 va à contre-courant de Java et de C #, pour le reste du langage. Il n'y a jamais rien que vous "supprimiez" explicitement, sauf si vous comptez explicitement rendre les choses plus privées qu'elles ne le seraient par défaut en Java.
L'option 4 est horrible - vous absolument voulez pouvoir forcer la construction avec certains paramètres. Que signifie même new FileStream()
?
Donc, en gros, if vous acceptez le principe selon lequel il est logique de fournir un constructeur par défaut, je pense qu'il est tout à fait logique de le supprimer dès que vous fournissez votre propre constructeur.
Modifier. En fait, bien que ce que je dis dans ma première réponse soit valable, voici la vraie raison:
Au début, il y avait C. Le C n'est pas orienté objet (vous pouvez adopter une approche OO, mais cela ne vous aide pas et ne fait rien imposer).
Ensuite, il y avait C With Classes, qui a ensuite été renommé C++. C++ est orienté objet, et encourage donc l'encapsulation, et assure un invariant d'objet - lors de la construction et au début et à la fin de toute méthode, l'objet est dans un état valide.
La chose naturelle à faire avec ceci est de faire en sorte qu'une classe ait toujours un constructeur pour s'assurer de démarrer dans un état valide - si le constructeur n'a rien à faire pour garantir cela, alors le constructeur vide documentera ce fait. .
Mais un objectif avec C++ devait être compatible avec C, au point que, dans la mesure du possible, tous les programmes C valides étaient également des programmes C++ valides (l’objectif n’était plus aussi actif, et l’évolution du C séparé en C++ signifie qu’il n’est plus valable. ).
Un des effets en a été la duplication des fonctionnalités entre struct
et class
. Les premiers font les choses à la manière C (tout le public est public par défaut) et les derniers font les choses bien OO (tout ce qui est privé par défaut, le développeur rend public ce qu'il veut public).
Une autre est que pour qu'une variable C struct
, qui ne puisse pas avoir de constructeur parce que C n'a pas de constructeurs, soit valide en C++, il devait alors y avoir un sens à la manière de la regarder en C++. Ainsi, alors que ne pas avoir de constructeur irait à l’encontre de la pratique OO consistant à assurer activement un invariant, C++ a interprété cela comme signifiant qu’il existait un constructeur sans paramètre par défaut qui agissait comme si son corps était vide.
Tous les C structs
étaient maintenant valides C++ structs
(ce qui signifiait qu'ils étaient identiques à C++ classes
avec tout - membres et héritage - public) traités de l'extérieur comme s'il ne possédait qu'un seul constructeur sans paramètre.
Toutefois, si vous avez placé un constructeur dans une variable class
ou struct
, vous utilisiez la méthode C++/OO plutôt que la méthode C et vous n'avez pas besoin d'un constructeur par défaut.
Comme cela servait de raccourci, les gens continuaient à l'utiliser même quand la compatibilité n'était pas possible autrement (il utilisait d'autres fonctionnalités C++ qui n'étaient pas en C).
Par conséquent, lorsque Java est apparu (basé sur le C++ à bien des égards) et plus tard, C # (basé sur le C++ et Java de différentes manières), ils ont conservé cette approche car les codeurs étaient peut-être déjà habitués.
Stroustrup écrit à ce sujet dans son Le langage de programmation C++ et plus encore, en mettant davantage l’accent sur les "pourquoi" du langage dans La conception et l’évolution du C++ .
=== Réponse originale ===
Disons que cela n'est pas arrivé.
Disons que je ne veux pas d'un constructeur sans paramètre, car je ne peux pas placer ma classe dans un état significatif sans un. En effet, c’est quelque chose qui peut arriver avec struct
en C # (mais si vous ne pouvez pas utiliser de manière significative un tout-zéros et des nulls struct
en C #, vous utilisez au mieux une optimisation non visible publiquement, et avoir un défaut de conception en utilisant struct
).
Pour que ma classe puisse protéger ses invariants, j'ai besoin d'un mot clé removeDefaultConstructor
spécial. À tout le moins, il me faudrait créer un constructeur privé sans paramètre pour m'assurer qu'aucun code appelant n'appelle par défaut.
Ce qui complique encore la langue. Mieux vaut ne pas le faire.
Dans l’ensemble, il vaut mieux ne pas penser à ajouter un constructeur comme supprimant le défaut, mais plutôt à ne pas avoir de constructeur du tout comme sucre syntaxique pour ajouter un constructeur sans paramètre qui ne fait rien.
Le constructeur par défaut sans paramètre est ajouté si vous ne faites rien vous-même pour prendre le contrôle de la création d'objet. Une fois que vous avez créé un seul constructeur pour prendre le contrôle, le compilateur "recule" et vous permet de disposer du contrôle total.
Si ce n'était pas le cas, vous auriez besoin d'un moyen explicite de désactiver le constructeur par défaut si vous voulez que les objets soient constructibles uniquement via un constructeur avec paramètres.
Je pense que la question devrait être l'inverse: Pourquoi n'avez-vous pas besoin de déclarer un constructeur par défaut si vous n'avez défini aucun autre constructeur?
Un constructeur est obligatoire pour les classes non statiques.
Donc, je pense que si vous n'avez défini aucun constructeur, le constructeur par défaut généré n'est qu'une fonctionnalité pratique du compilateur C #, votre classe ne serait pas valide sans constructeur. Donc, rien à redire à générer implicitement un constructeur qui ne fait rien. Cela semble certainement plus propre que d'avoir des constructeurs vides tout autour.
Si vous avez déjà défini un constructeur, votre classe est valide, alors pourquoi le compilateur devrait-il supposer que vous voulez un constructeur par défaut? Et si vous n'en voulez pas? Implémenter un attribut pour dire au compilateur de ne pas générer ce constructeur par défaut? Je ne pense pas que ce serait une bonne idée.
C'est une fonction pratique du compilateur . Si vous définissez un constructeur avec des paramètres mais ne définissez pas un constructeur sans paramètre, la possibilité que vous ne souhaitiez pas autoriser un constructeur sans paramètre est beaucoup plus grande.
C'est le cas de nombreux objets pour lesquels l'initialisation avec un constructeur vide n'a aucun sens.
Sinon, vous devrez déclarer un constructeur privé sans paramètre pour chaque classe que vous souhaitez restreindre.
À mon avis, ce n'est pas un bon style d'autoriser un constructeur sans paramètre pour une classe qui a besoin de paramètres pour fonctionner.
Le constructeur par défaut ne peut être construit que lorsque la classe n'a pas de constructeur. Les compilateurs sont écrits de manière à ne fournir cela que comme mécanisme de sauvegarde.
Si vous avez un constructeur paramétré, vous ne voudrez peut-être pas qu'un objet soit créé à l'aide du constructeur par défaut. Si le compilateur avait fourni un constructeur par défaut, vous auriez dû écrire un constructeur no-arg et le rendre privé afin d'empêcher la création d'objets sans argument.
En outre, vous risqueriez davantage d'oublier de désactiver ou de "privatiser" le constructeur par défaut, ce qui entraînerait une erreur fonctionnelle potentielle difficile à détecter.
Et maintenant, vous devez définir explicitement un constructeur no-arg si vous souhaitez qu'un objet soit créé par défaut ou en transmettant des paramètres. Ceci est fortement vérifié et le compilateur se plaint du contraire, assurant ainsi qu'il n'y a pas de faille ici.
Je pense que cela est géré par le compilateur. Si vous ouvrez l'assembly .net
dans ILDASM
, vous verrez le constructeur par défaut, même s'il ne figure pas dans le code. Si vous définissez un constructeur paramétré, le constructeur par défaut ne sera pas visible.
En fait, lorsque vous définissez la classe (non statique), le compilateur fournit cette fonctionnalité en pensant que vous allez simplement créer une instance. Et si vous souhaitez effectuer une opération spécifique, vous aurez sûrement votre propre constructeur.
Local
Ce comportement peut être considéré comme une extension naturelle de la décision pour que les classes aient un constructeur public sans paramètre par défaut. Sur la base de la question qui a été posée, nous prenons cette décision comme prémisse et supposons que nous ne la remettons pas en question dans ce cas.
Méthodes pour supprimer le constructeur par défaut
Il s'ensuit qu'il doit exister un moyen de supprimer le constructeur sans paramètre public par défaut. Cette suppression peut être réalisée des manières suivantes:
Choisir la meilleure solution
Maintenant nous nous demandons: S'il n'y a pas de constructeur sans paramètre, par quoi faut-il le remplacer? et Dans quels types de scénarios voudrions-nous supprimer le constructeur sans paramètre public par défaut?
Les choses commencent à tomber en place. Premièrement, il doit être remplacé par un constructeur avec des paramètres ou par un constructeur non public. Deuxièmement, les scénarios dans lesquels vous ne souhaitez pas de constructeur sans paramètre sont les suivants:
Conclusion
Voilà ce que nous avons - exactement les deux manières par lesquelles C #, C++ et Java autorisent la suppression du constructeur public sans paramètre par défaut.
C'est parce que lorsque vous ne définissez pas de constructeur, le compilateur génère automatiquement un constructeur qui ne prend aucun argument. Lorsque vous voulez quelque chose de plus d'un constructeur, vous le remplacez. Ce n'est PAS une surcharge de fonction. Le seul constructeur que le compilateur voit maintenant est donc votre constructeur qui prend un argument. Pour contrer ce problème, vous pouvez passer une valeur par défaut si le constructeur est passé sans valeur.
Une classe a besoin d'un constructeur. C'est une exigence obligatoire.
Je vais répondre à votre question avec un autre, pourquoi voulons-nous toujours un constructeur par défaut sans paramètre? Dans certains cas, cela n’est pas souhaité et le développeur a le contrôle de l’ajouter ou de le supprimer si nécessaire.