En C #, C ++ y Java, cuando crea un constructor que toma parámetros, el sin parámetros predeterminado desaparece. Siempre he aceptado este hecho, pero ahora he empezado a preguntarme por qué.
¿Cuál es la razón de este comportamiento? ¿Es solo una "medida de seguridad / adivinanza" que dice "Si ha creado un constructor propio, probablemente no quiera que este implícito esté dando vueltas"? ¿O tiene una razón técnica que hace imposible que el compilador agregue uno una vez que haya creado un constructor usted mismo?
c#
java
c++
default-constructor
olagjo
fuente
fuente
Foo() = default;
que recupere el predeterminado.Respuestas:
No hay razón para que el compilador no pueda agregar el constructor si ha agregado el suyo, ¡el compilador podría hacer casi lo que quiera! Sin embargo, debes mirar lo que tiene más sentido:
Entonces, en cada caso, puede ver que el comportamiento de los compiladores actuales tiene más sentido en términos de preservar la intención probable del código.
fuente
Ciertamente no hay una razón técnica por la cual el lenguaje tiene que ser diseñado de esta manera.
Hay cuatro opciones algo realistas que puedo ver:
La opción 1 es algo atractiva, ya que cuanto más codifico, con menos frecuencia realmente quiero un constructor sin parámetros. Algún día debería contar la frecuencia con la que realmente termino usando un constructor predeterminado ...
Opción 2 con la que estoy bien.
La opción 3 va en contra del flujo de Java y C #, para el resto del lenguaje. Nunca hay nada que "elimine" explícitamente, a menos que cuente explícitamente hacer las cosas más privadas de lo que serían por defecto en Java.
La opción 4 es horrible: absolutamente desea poder forzar la construcción con ciertos parámetros. ¿Qué
new FileStream()
significaría incluso?Básicamente, si acepta la premisa de que proporcionar un constructor predeterminado tiene sentido, creo que tiene mucho sentido suprimirlo tan pronto como proporcione su propio constructor.
fuente
struct
s, para bien o para mal.Editar. En realidad, aunque lo que digo en mi primera respuesta es válido, esta es la verdadera razón:
Al principio existía C. C no está orientado a objetos (puede adoptar un enfoque OO, pero no lo ayuda ni impone nada).
Luego estaba C With Classes, que luego pasó a llamarse C ++. C ++ está orientado a objetos y, por lo tanto, fomenta la encapsulación y garantiza la invariabilidad de un objeto: después de la construcción y al principio y al final de cualquier método, el objeto está en un estado válido.
Lo natural que se debe hacer con esto es hacer cumplir que una clase siempre debe tener un constructor para garantizar que comience en un estado válido; si el constructor no tiene que hacer nada para garantizarlo, el constructor vacío documentará este hecho. .
Pero un objetivo con C ++ era ser compatible con C hasta el punto de que, en la medida de lo posible, todos los programas válidos de C también eran programas válidos de C ++ (ya no es un objetivo tan activo, y la evolución de C separada de C ++ significa que ya no se cumple )
Un efecto de esto fue la duplicación en la funcionalidad entre
struct
yclass
. El primero hace las cosas a la manera C (todo público por defecto) y el segundo hace las cosas de una buena manera OO (todo lo privado por defecto, el desarrollador hace público lo que quiere público).Otra es que para que una C
struct
, que no podría tener un constructor porque C no tiene constructores, sea válida en C ++, tenía que haber un significado para esto en la forma de verla en C ++. Y así, aunque no tener un constructor iría en contra de la práctica OO de asegurar activamente una invariante, C ++ tomó esto como que significaba que había un constructor sin parámetros predeterminado que actuaba como si tuviera un cuerpo vacío.Todos los C
structs
ahora eran C ++ válidosstructs
, (lo que significaba que eran lo mismo que C ++classes
con todo, miembros y herencia, público) tratados desde el exterior como si tuviera un único constructor sin parámetros.Sin embargo, si puso un constructor en una
class
ostruct
, entonces estaba haciendo las cosas de la manera C ++ / OO en lugar de la forma C, y no había necesidad de un constructor predeterminado.Dado que sirvió como una abreviatura, la gente siguió usándolo incluso cuando la compatibilidad no era posible de otra manera (usaba otras características de C ++ que no estaban en C).
Por lo tanto, cuando apareció Java (basado en C ++ de muchas maneras) y luego C # (basado en C ++ y Java de diferentes maneras), mantuvieron este enfoque como algo a lo que los codificadores ya pueden estar acostumbrados.
Stroustrup escribe sobre esto en su lenguaje de programación The C ++ y aún más, con un mayor enfoque en los "porqués" del lenguaje en The Design and Evolution of C ++ .
=== Respuesta original ===
Digamos que esto no sucedió.
Digamos que no quiero un constructor sin parámetros, porque no puedo poner mi clase en un estado significativo sin uno. De hecho, esto es algo que puede suceder
struct
en C # (pero si no puede hacer un uso significativo de todos ceros y nulosstruct
en C #, en el mejor de los casos, está utilizando una optimización no visible públicamente y, de lo contrario, tiene un falla de diseño en el usostruct
).Para que mi clase pueda proteger a sus invariantes, necesito una
removeDefaultConstructor
palabra clave especial . Por lo menos, necesitaría crear un constructor privado sin parámetros para asegurarme de que ningún código de llamada llame al valor predeterminado.Lo que complica aún más el lenguaje. Mejor no hacerlo.
En general, es mejor no pensar en agregar un constructor como eliminar el valor predeterminado, mejor pensar en no tener ningún constructor como azúcar sintáctica para agregar un constructor sin parámetros que no haga nada.
fuente
El constructor sin parámetros predeterminado se agrega si no hace nada usted mismo para tomar el control sobre la creación de objetos. Una vez que haya creado un solo constructor para tomar el control, el compilador "retrocede" y le permite tener el control total.
Si no fuera así, necesitaría alguna forma explícita de deshabilitar el constructor predeterminado si solo desea que los objetos sean construibles a través de un constructor con parámetros.
fuente
Es una función de conveniencia del compilador. Si define un constructor con parámetros pero no define un constructor sin parámetros, la posibilidad de que no desee permitir un constructor sin parámetros es mucho mayor.
Este es el caso de muchos objetos que simplemente no tienen sentido inicializar con un constructor vacío.
De lo contrario, tendría que declarar un constructor privado sin parámetros para cada clase que desee restringir.
En mi opinión, no es un buen estilo permitir un constructor sin parámetros para una clase que necesita parámetros para funcionar.
fuente
Creo que la pregunta debería ser al revés: ¿por qué no necesita declarar un constructor predeterminado si no ha definido ningún otro constructor?
Un constructor es obligatorio para las clases no estáticas.
Así que creo que si no ha definido ningún constructor, el constructor predeterminado generado es solo una característica conveniente del compilador de C #, además su clase no sería válida sin un constructor. Entonces, no hay nada malo en generar implícitamente un constructor que no hace nada. Ciertamente se ve más limpio que tener constructores vacíos por todas partes.
Si ya ha definido un constructor, su clase es válida, entonces, ¿por qué el compilador debería suponer que desea un constructor predeterminado? ¿Qué pasa si no quieres uno? ¿Implementar un atributo para decirle al compilador que no genere ese constructor predeterminado? No creo que sea una buena idea.
fuente
El constructor predeterminado solo se puede construir cuando la clase no tiene un constructor. Los compiladores están escritos de tal manera que solo se proporcionan como un mecanismo de respaldo.
Si tiene un constructor parametrizado, es posible que no desee que se cree un objeto utilizando el constructor predeterminado. Si el compilador hubiera proporcionado un constructor predeterminado, habría tenido que escribir un constructor sin argumentos y hacerlo privado para evitar que los objetos se creen sin argumentos.
Además, habría mayores posibilidades de que olvides deshabilitar o 'privatizar' el constructor predeterminado y, por lo tanto, causar un posible error funcional difícil de detectar.
Y ahora tiene que definir explícitamente un constructor sin argumentos si desea que se cree un objeto de forma predeterminada o pasando parámetros. Esto se verifica fuertemente y el compilador se queja de lo contrario, asegurando así que no haya escapatorias aquí.
fuente
Premisa
Este comportamiento puede verse como una extensión natural de la decisión de las clases de tener un constructor público sin parámetros predeterminado . En función de la pregunta que se nos formula, tomamos esta decisión como premisa y asumimos que no la estamos cuestionando en este caso.
Formas de eliminar el constructor predeterminado
Se deduce que debe haber una manera de eliminar el constructor público sin parámetros predeterminado. Esta eliminación podría llevarse a cabo de las siguientes maneras:
Seleccionando la mejor solución
Ahora nos preguntamos: si no hay un constructor sin parámetros, ¿por qué debe ser reemplazado? y ¿Bajo qué tipos de escenarios querríamos eliminar el constructor público sin parámetros predeterminado?
Las cosas comienzan a ponerse en su lugar. En primer lugar, debe reemplazarse con un constructor con parámetros o con un constructor no público. En segundo lugar, los escenarios en los que no desea un constructor sin parámetros son:
Conclusión
Ahí lo tenemos, exactamente las dos formas en que C #, C ++ y Java permiten la eliminación del constructor público sin parámetros predeterminado.
fuente
= delete
para este propósito.Creo que esto es manejado por el compilador. Si abre el
.net
ensamblajeILDASM
, verá el constructor predeterminado, incluso si no está en el código. Si define un constructor parametrizado, no se verá el constructor predeterminado.En realidad, cuando define la clase (no estática), el compilador proporciona esta característica pensando que solo creará una instancia. Y si desea realizar una operación específica, seguramente tendrá su propio constructor.
fuente
Es porque cuando no define un constructor, el compilador genera automáticamente un constructor para usted que no toma ningún argumento. Cuando quieres algo más de un constructor, lo anulas. Esto NO es sobrecarga de funciones. Entonces, el único constructor que el compilador ve ahora es su constructor que toma un argumento. Para contrarrestar este problema, puede pasar un valor predeterminado si el constructor se pasa sin ningún valor.
fuente
Una clase necesita un constructor. Es requisito obligatorio.
Contestaré su pregunta con otra, ¿por qué queremos siempre un constructor sin parámetros predeterminado? hay casos en los que esto no se desea, por lo que el desarrollador tiene el control para agregarlo o eliminarlo según sea necesario.
fuente