En C #, C ++ et Java, lorsque vous créez un constructeur prenant des paramètres, celui sans paramètre par défaut disparaît. J'ai toujours juste accepté ce fait, mais maintenant j'ai commencé à me demander pourquoi.
Quelle est la raison de ce comportement? Est-ce juste une "mesure de sécurité / supposition" disant "Si vous avez créé votre propre constructeur, vous ne voulez probablement pas que celui-ci traîne"? Ou y a-t-il une raison technique qui empêche le compilateur d'en ajouter un une fois que vous avez vous-même créé un constructeur?
c#
java
c++
default-constructor
Olagjo
la source
la source
Foo() = default;
de récupérer celui par défaut.Réponses:
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 a le plus de sens:
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.
la source
Il n'y a certainement aucune raison technique pour laquelle le langage doit être conçu de cette façon.
Il y a quatre options quelque peu réalistes que je peux voir:
L'option 1 est quelque peu attrayante, en ce sens que plus je code, moins je veux vraiment d'un constructeur sans paramètre. Un jour, je devrais compter à quelle fréquence je finis par utiliser un constructeur par défaut ...
Option 2 Je suis d'accord.
L'option 3 va à l'encontre du flux de Java et de C #, pour le reste du langage. Il n'y a jamais rien que vous «supprimiez» explicitement, à moins que vous ne comptiez explicitement rendre les choses plus privées qu'elles ne le seraient par défaut en Java.
L'option 4 est horrible - vous voulez absolument pouvoir forcer la construction avec certains paramètres. Que
new FileStream()
signifierait même?Donc, fondamentalement, si vous acceptez la prémisse selon laquelle fournir un constructeur par défaut a du sens, je pense qu'il est très logique de le supprimer dès que vous fournissez votre propre constructeur.
la source
struct
, pour le meilleur ou pour le pire.Éditer. En fait, bien que ce que je dis dans ma première réponse soit valable, c'est la vraie raison:
Au début, il y avait C. C n'est pas orienté objet (vous pouvez adopter une approche OO, mais cela ne vous aide pas ou n'applique rien).
Ensuite, il y a eu C With Classes, qui a ensuite été renommé C ++. Le C ++ est orienté objet, et encourage donc l'encapsulation, et garantit l'invariant d'un 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 cela, est de faire en sorte qu'une classe doit toujours avoir un constructeur pour s'assurer qu'elle démarre 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 ++ était d'être compatible avec C au point que, dans la mesure du possible, tous les programmes C valides étaient également des programmes C ++ valides (ce n'est plus un objectif aussi actif, et l'évolution du C séparée vers C ++ signifie qu'il ne tient plus) ).
Un effet de ceci était la duplication des fonctionnalités entre
struct
etclass
. Le premier fait les choses à la manière C (tout est public par défaut) et le second fait les choses d'une bonne manière OO (tout est privé par défaut, le développeur rend activement public ce qu'il veut).Un autre est que pour qu'un C
struct
, qui ne pouvait pas avoir de constructeur parce que C n'a pas de constructeurs, soit valide en C ++, alors il devait y avoir une signification pour cela à la manière C ++ de le voir. Et donc, bien que ne pas avoir de constructeur irait à l'encontre de la pratique OO d'assurer activement un invariant, C ++ a pris cela pour signifier qu'il y avait un constructeur sans paramètre par défaut qui agissait comme s'il avait un corps vide.Tous les C
structs
étaient désormais des C ++ validesstructs
, (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 avait un seul constructeur sans paramètre.Si toutefois vous avez mis un constructeur dans un
class
oustruct
, alors vous faisiez les choses de la manière C ++ / OO plutôt que de la manière C, et il n'y avait pas besoin d'un constructeur par défaut.Puisqu'il servait de raccourci, les gens continuaient à l'utiliser même lorsque la compatibilité n'était pas possible autrement (il utilisait d'autres fonctionnalités C ++ pas en C).
Par conséquent, lorsque Java est arrivé (basé sur C ++ à bien des égards) et plus tard C # (basé sur 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 The C ++ Programming Language et plus encore, avec plus d'attention sur les «pourquoi» du langage dans The Design and Evolution of C ++ .
=== Réponse originale ===
Disons que cela ne s'est pas produit.
Disons que je ne veux pas d'un constructeur sans paramètre, car je ne peux pas mettre 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 tous les zéros et les nulsstruct
en C #, vous utilisez au mieux une optimisation non visible publiquement, et sinon défaut de conception lors de l'utilisationstruct
).Pour rendre ma classe capable de protéger ses invariants, j'ai besoin d'un
removeDefaultConstructor
mot-clé spécial . À tout le moins, je devrais créer un constructeur privé sans paramètre pour m'assurer qu'aucun code d'appel n'appelle la valeur 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 la valeur par défaut, mieux vaut penser à ne pas avoir de constructeur du tout comme du sucre syntaxique pour ajouter un constructeur sans paramètre qui ne fait rien.
la source
Le constructeur sans paramètre par défaut 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 laisse le 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 uniquement que les objets soient constructibles via un constructeur avec des paramètres.
la source
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 élevée.
C'est le cas de nombreux objets qui n'ont tout simplement pas de sens à s'initialiser avec un constructeur vide.
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.
la source
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é est juste une fonctionnalité pratique du compilateur C #, et votre classe ne serait pas valide sans constructeur. Donc rien de mal à générer implicitement un constructeur qui ne fait rien. Cela a certainement l'air 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.
la source
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 souhaitez 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 sans argument et le rendre privé afin d'empêcher la création d'objets en utilisant aucun argument.
En outre, il y aurait plus de chances que vous oubliez de désactiver ou de «privatiser» le constructeur par défaut, et de provoquer ainsi une erreur fonctionnelle potentielle difficile à détecter.
Et maintenant, vous devez définir explicitement un constructeur sans argument si vous souhaitez qu'un objet soit créé de la manière par défaut ou en passant des paramètres. Ceci est fortement vérifié et le compilateur se plaint du contraire, assurant ainsi aucune faille ici.
la source
Prémisse
Ce comportement peut être vu comme une extension naturelle de la décision des classes d'avoir un constructeur sans paramètre public par défaut . Sur la base de la question posée, nous prenons cette décision comme une prémisse et supposons que nous ne la remettons pas en question dans ce cas.
Méthodes de suppression du constructeur par défaut
Il s'ensuit qu'il doit y avoir un moyen de supprimer le constructeur sans paramètre public par défaut. Cette suppression peut être effectué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 doit-il être remplacé? et Dans quels types de scénarios voudrions-nous supprimer le constructeur sans paramètre public par défaut?
Les choses commencent à se mettre en place. Premièrement, il doit être soit remplacé par un constructeur avec des paramètres, soit par un constructeur non public. Deuxièmement, les scénarios dans lesquels vous ne voulez pas d'un constructeur sans paramètre sont:
Conclusion
Voilà, exactement les deux façons dont C #, C ++ et Java permettent la suppression du constructeur sans paramètre public par défaut.
la source
= delete
à cette fin.Je pense que cela est géré par le compilateur. Si vous ouvrez l'
.net
assembly 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 vu.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 exécuter une opération spécifique, vous aurez sûrement votre propre constructeur.
la source
C'est parce que lorsque vous ne définissez pas de constructeur, le compilateur génère automatiquement un constructeur pour vous qui ne prend aucun argument. Lorsque vous voulez quelque chose de plus de la part d'un constructeur, vous le remplacez. Ce n'est PAS une surcharge de fonction. Donc, le seul constructeur que le compilateur voit maintenant est votre constructeur qui prend un argument. Pour contrer ce problème, vous pouvez transmettre une valeur par défaut si le constructeur est passé sans valeur.
la source
Une classe a besoin d'un constructeur. C'est une exigence obligatoire.
Je vais répondre à votre question par une autre, pourquoi voulons-nous toujours un constructeur sans paramètre par défaut? il y a des cas où cela n'est pas souhaité, de sorte que le développeur a le contrôle pour l'ajouter ou le supprimer selon ses besoins.
la source