Почему конструктор без параметров по умолчанию исчезает, когда вы создаете его с параметрами

В С#, С++ и Java, когда вы создаете конструктор, принимающий параметры, по умолчанию без параметров он исчезает. Я всегда принимал этот факт, но теперь я начал задаваться вопросом, почему.

В чем причина такого поведения? Это всего лишь "мера безопасности/догадка", говорящая "Если вы создали свой собственный конструктор, вы, вероятно, не хотите, чтобы этот неявный человек висел"? Или у него есть техническая причина, из-за которой невозможно добавить компилятор сразу после создания конструктора самостоятельно?

Ответ 1

Нет причин, чтобы компилятор не мог добавить конструктор, если вы добавили свой собственный - компилятор мог бы делать все, что захочет! Однако вам нужно взглянуть на то, что имеет наибольший смысл:

  • Если я не определил какой-либо конструктор для нестатического класса, я, скорее всего, захочу создать экземпляр этого класса. Чтобы это разрешить, компилятор должен добавить конструктор без параметров, который не будет иметь никакого эффекта, но позволит создать экземпляр. Это означает, что мне не нужно включать пустой код в код, чтобы он работал.
  • Если я определил свой собственный конструктор, особенно один с параметрами, то у меня, скорее всего, есть своя логика, которая должна быть выполнена при создании класса. Если в этом случае компилятор должен был создать пустой конструктор без параметров, он позволил бы кому-то пропустить написанную мной логику, что может привести к нарушению моего кода во многих отношениях. Если в этом случае мне нужен пустой конструктор по умолчанию, я должен сказать это явно.

Итак, в каждом случае вы можете видеть, что поведение текущих компиляторов имеет наибольший смысл с точки зрения сохранения вероятного намерения кода.

Ответ 2

Разумеется, нет технической причины, по которой язык должен быть разработан таким образом.

Есть четыре несколько реалистичных варианта, которые я вижу:

  • Нет конструкторов по умолчанию вообще
  • Текущий сценарий
  • По умолчанию всегда предоставляется конструктор по умолчанию, но он явно запрещен
  • Всегда предоставлять конструктор по умолчанию, не позволяя ему подавляться.

Вариант 1 несколько привлекателен тем, что чем больше я кодирую, тем меньше я действительно хочу конструктор без параметров. В какой-то день мне следует подсчитать, как часто я на самом деле использую конструктор по умолчанию...

Вариант 2 У меня все хорошо.

Вариант 3 идет против потока как Java, так и С# для остальной части языка. Там никогда не было ничего, что вы явно "удаляете", если только вы не подсчитаете явно, делая вещи более закрытыми, чем они были бы по умолчанию в Java.

Вариант 4 ужасен - вы абсолютно хотите иметь возможность форсировать конструкцию с определенными параметрами. Что означает new FileStream()?

Итак, в принципе, если вы согласны с предпосылкой, что предоставление конструктора по умолчанию имеет смысл вообще, я считаю, что имеет смысл подавить его, как только вы предоставите свой собственный конструктор.

Ответ 3

Изменить. На самом деле, хотя то, что я говорю в своем первом ответе, действительно, это настоящая причина.:

В начале было C. C не является объектно-ориентированным (вы можете использовать OO-подход, но это не поможет вам или не навязывает что-либо).

Затем был C С классами, который позже был переименован в С++. С++ объектно-ориентирован и поэтому поощряет инкапсуляцию и обеспечивает инвариант объекта - при построении и в начале и в конце любого метода объект находится в допустимом состоянии.

Естественное дело в этом состоит в том, чтобы обеспечить, чтобы класс всегда имел конструктор, чтобы гарантировать, что он запускается в правильном состоянии - если конструктор не должен ничего делать, чтобы обеспечить это, то пустой конструктор будет документируйте этот факт.

Но цель с С++ заключалась в том, чтобы быть совместимой с C до такой степени, насколько это было возможно, все действующие C-программы были также действительными С++-программами (уже не так активно, а эволюция C, отдельная для С++, означает больше не выполняется).

Одним из последствий этого было дублирование в функциональности между struct и class. Первый делает вещи C образом (все по умолчанию по умолчанию), а последний делает что-то в хорошем способе OO (все по-умолчанию по умолчанию разработчик активно публикует то, что они хотят публично).

Другим является то, что для C struct, который не может иметь конструктор, потому что у C нет конструкторов, чтобы быть допустимым в С++, тогда для этого должен был быть смысл для С++ глядя на него. И поэтому, не имея конструктора, будет идти против OO-практики активного обеспечения инварианта, С++ подразумевает, что существует конструктор без параметров, который поступил так, будто у него было пустое тело.

Все C structs теперь были действительны С++ structs (что означало, что они были такими же, как С++ classes со всем - членами и наследованием - public), обработанными извне, как если бы у него был единственный конструктор без параметров.

Если, однако, вы поместили конструктор в class или struct, тогда вы делали вещи как путь С++/OO, а не путь C, и не было необходимости в конструкторе по умолчанию.

Поскольку он служил сокращением, люди продолжали использовать его, даже если совместимость невозможна в противном случае (она использовала другие функции С++ не в C).

Следовательно, когда Java приходила (на основе С++ по-разному), а позже С# (на основе С++ и Java по-разному), они придерживались такого подхода, поскольку уже могут быть использованы кодеры.

Stroustrup пишет об этом на своем языке программирования С++ и тем более, уделяя больше внимания "whys" языка в "Design and Evolution of С++".

=== Оригинальный ответ ===

Скажем, этого не произошло.

Скажем, мне не нужен конструктор без параметров, потому что я не могу поставить свой класс в полноценное состояние без него. В самом деле, это то, что может произойти с struct в С# (но если вы не можете сделать значимое использование all-zeros-and-nulls struct в С#, вы в лучшем случае используете непублично видимые оптимизация и, в противном случае, иметь конструктивную ошибку при использовании struct).

Чтобы мой класс мог защитить свои инварианты, мне нужно специальное ключевое слово removeDefaultConstructor. По крайней мере, мне нужно создать частный конструктор без параметров, чтобы убедиться, что вызывающий код не вызывает по умолчанию.

Что еще более усложняет язык. Лучше не делать этого.

В целом, лучше не думать о добавлении конструктора как об удалении по умолчанию, лучше думать о отсутствии конструктора вообще как синтаксического сахара для добавления конструктора без параметров, который ничего не делает.

Ответ 4

Добавленный конструктор без параметров добавляется, если вы ничего не предпринимаете сами, чтобы взять управление над созданием объекта. После того, как вы создали единый конструктор для управления, компилятор "отступает" и позволяет вам полностью контролировать.

Если это не так, вам понадобится какой-то явный способ отключить конструктор по умолчанию, если вы хотите, чтобы объекты были конструктивны с помощью конструктора с параметрами.

Ответ 5

Я думаю, что вопрос должен быть наоборот: почему вам не нужно объявлять конструктор по умолчанию, если вы не определили каких-либо других конструкторов?

Конструктор является обязательным для нестатических классов.
Поэтому я думаю, что если вы не определили каких-либо конструкторов, созданный конструктор по умолчанию является просто удобной функцией компилятора С#, также ваш класс не будет действителен без конструктора. Так что ничего плохого в том, что неявно генерирует конструктор, который ничего не делает. Это, безусловно, выглядит чище, чем пустые конструкторы.

Если вы уже определили конструктор, ваш класс действителен, поэтому почему компилятор предполагает, что вы хотите использовать конструктор по умолчанию? Что, если ты этого не хочешь? Внедрить атрибут, чтобы сообщить компилятору не генерировать этот конструктор по умолчанию? Я не думаю, что это была бы хорошая идея.

Ответ 6

Это удобная функция компилятора. Если вы определяете конструктор с параметрами, но не определяете конструктор без параметров, вероятность того, что вы не хотите разрешать конструктор без параметров, намного выше.

Это относится ко многим объектам, которые просто не имеют смысла инициализировать с помощью пустого конструктора.

В противном случае вам придется объявить частный конструктор без параметров для каждого класса, который вы хотите ограничить.

По-моему, это нехороший стиль, позволяющий безпараметрическому конструктору для класса, которому нужны параметры для работы.

Ответ 7

Конструктор по умолчанию может быть создан только тогда, когда класс не имеет конструктора. Компиляторы записываются таким образом, чтобы обеспечить это только как резервный механизм.

Если у вас есть параметризованный конструктор, вы можете не захотеть создать объект с помощью конструктора по умолчанию. Если бы компилятор предоставил конструктор по умолчанию, вам пришлось бы написать конструктор no-arg и сделать его закрытым, чтобы предотвратить создание объектов без аргументов.

Кроме того, у вас будет больше шансов забыть об отключении или "приватизировать" конструктор по умолчанию и тем самым затруднить потенциальную функциональную ошибку.

И теперь вам нужно явно определить конструктор no-arg, если вы хотите, чтобы объект был создан либо способом по умолчанию, либо передачей параметров. Это сильно проверяется, и компилятор жалуется иначе, тем самым обеспечивая отсутствие лазейки здесь.

Ответ 8

Предпосылка

Это поведение можно рассматривать как естественное расширение решения для классов с открытым стандартным конструктором без параметров. Исходя из вопроса, который был задан, мы принимаем это решение в качестве предпосылки и предполагаем, что мы не ставим под сомнение его в этом случае.

Способы удаления конструктора по умолчанию

Из этого следует, что должен быть способ удалить стандартный конструктор без параметров. Это удаление может быть выполнено следующими способами:

  • Объявить непубличный конструктор без параметров
  • Автоматически удалять конструктор без параметров, когда объявляется конструктор с параметрами
  • Некоторое ключевое слово/атрибут, указывающий компилятору на удаление конструктора без параметров (неудобно, что его легко исключить)

Выбор лучшего решения

Теперь мы спрашиваем себя: если нет конструктора без параметров, что его нужно заменить? и В каких сценариях мы хотели бы удалить стандартный конструктор без параметров по умолчанию?

Вещи начинают падать. Во-первых, он должен быть заменен конструктором с параметрами или с непубличным конструктором. Во-вторых, сценарии, при которых вы не хотите конструктор без параметров:

  • Мы не хотим, чтобы класс создавался вообще, или мы хотим контролировать видимость конструктора: объявить непубличный конструктор
  • Мы хотим принудительно предоставить параметры для построения: объявить конструктор с параметрами

Заключение

У нас есть это - два способа, с помощью которых С#, С++ и Java позволяют удалить стандартный конструктор без параметров.

Ответ 9

Я думаю, что это обрабатывается компилятором. Если вы откроете сборку .net в ILDASM, вы увидите конструктор по умолчанию, даже если он не в коде. Если вы определяете параметризованный конструктор, конструктор по умолчанию не будет отображаться.

Фактически, когда вы определяете класс (не статический), компилятор предоставляет эту функцию, думая, что вы просто создадите экземпляр. И если вы хотите, чтобы какая-либо конкретная операция выполнялась, вы наверняка будете иметь свой собственный конструктор.

Ответ 10

Потому что, когда вы не определяете конструктор, компилятор автоматически генерирует для вас конструктор, который не принимает никаких аргументов. Когда вы хотите получить что-то еще от конструктора, вы переверните его. Это НЕ перегрузка функции. Таким образом, единственный конструктор, который видит компилятор, теперь является вашим конструктором, который принимает аргумент. Чтобы противостоять этой проблеме, вы можете передать значение по умолчанию, если конструктор передан без значения.