poo - Herencia OOP y constructor predeterminado
herencia poo (3)
Ahora, al crear una nueva instancia de la clase
B
, ¿a qué constructor de la claseA
se llama automáticamente antes de invocar al constructor de la claseB
?
El código no podrá compilar, básicamente. Cada constructor tiene que encadenarse a otro constructor, implícita o explícitamente. El constructor al que encadena puede estar en la misma clase (con this
) o la clase base (con base
).
Un constructor como este:
public B() {}
es implícitamente
public B() : base() {}
... y si no especifica ningún constructor, se agregará implícitamente de la misma manera, pero aún debe tener algo para llamar. Entonces, por ejemplo, su escenario:
public class A
{
public A(int x) {}
}
public class B : A {}
conduce a un error de compilación de:
error CS7036: no se da ningún argumento que corresponda al parámetro formal requerido
''x''
de''AA(int)''
Sin embargo, puede especificar una llamada de constructor diferente explícitamente, por ejemplo
public B() : base(10) {} // Chain to base class constructor
o
public B() : this(10) {} // Chain to same class constructor, assuming one exists
Supongamos que hay una clase base A
y una clase B
derivada de A
Entonces, sabemos que el constructor de la clase A
nunca es heredado por la clase B
Sin embargo, cuando se crea un nuevo objeto de B
, se llama al constructor predeterminado de la clase A
antes de que se invoque el constructor predeterminado / personalizado de la clase B
Quizás el propósito de esto es que los campos de la clase A
deben inicializarse a los valores predeterminados.
Ahora, supongamos que la clase A
ha definido un constructor personalizado. Esto significa que el compilador elimina silenciosamente el constructor predeterminado de la clase A
Ahora, al crear una nueva instancia de la clase B
, ¿a qué constructor de la clase A
se llama automáticamente antes de invocar el constructor de la clase B
? (¿Cómo se inicializan los campos de clase A
en tal caso?)
Cuando un constructor completa la ejecución, el objeto está en un estado inicial válido. Se supone que debemos usar objetos que sean válidos.
Cuando proporcionamos un constructor no predeterminado para la clase A, estamos diciendo efectivamente, para construir el objeto de la clase A, es decir, para estar en el estado inicial válido, necesitamos más información, que es proporcionada por los parámetros.
Dado esto, el compilador ayuda al no generar el constructor predeterminado. El código del cliente no compilará (como debería, ¿de qué otra forma haremos que el objeto aterrice en un estado válido?) Y el programador cliente tendría que sentarse y darse cuenta.
Cuando proporcionas un constructor vacío explícito, estás diciendo efectivamente al compilador, sé lo que estoy haciendo, el constructor predeterminado muy probablemente inicialice los campos con algunos valores predeterminados razonables.
O para promover la reutilización: el constructor predeterminado puede llamar al no predeterminado con algunos valores predeterminados.
Una subclase conoce su superclase: un constructor de subclase puede invocar métodos de superclase (algunos métodos comúnmente reutilizados en subclases). Dado lo anterior, esto requiere que la parte de la superclase esté en un estado válido, es decir, su constructor se ejecutó antes de invocar el método . Esto requiere llamar al superconstructor antes del constructor de subclase.
Dado esto, podrá diseñar fácilmente su constructor para aplicar el comportamiento de estado inicial correcto.
Una vez que proporcione su propio constructor a la class A
, no se producirán invocaciones automáticas durante la creación del objeto class B
La primera línea del constructor de su class B
debe ser super(paramsToClassAConstructor)
o puede llamar a otro constructor con la class B
usando this()
. Es responsabilidad del segundo constructor en la class B
llamar al constructor class A
en ese caso.