С# наследование и конструкторы по умолчанию
Предположим, что существует базовый класс A
и класс B
, полученный из A
.
Затем мы знаем, что конструктор класса A
никогда не наследуется классом B
. Однако, когда создается новый объект B
, тогда - конструктор по умолчанию класса A
вызывается до того, как по умолчанию/пользовательский конструктор класса B
вызывается. Возможно, целью этого является то, что поля класса A
должны быть инициализированы значениями по умолчанию.
Теперь предположим, что класс A
определил пользовательский конструктор. Это означает, что конструктор по умолчанию класса A
молча удаляется компилятором. Теперь, при создании нового экземпляра класса B
, какой конструктор класса A
автоматически вызывается перед вызовом конструктора class B
? (Как поля класса A
получают инициализацию в таком случае?)
Ответы
Ответ 1
Теперь, при создании нового экземпляра класса B
, какой конструктор класса A
автоматически вызывается перед вызовом конструктора класса B
?
В общем случае код не будет скомпилирован. Каждый конструктор должен привязываться к другому конструктору, как неявно, так и явно. Конструктор, к которому он привязан, может находиться в одном классе (с this
) или базовым классом (с base
).
Конструктор, подобный этому:
public B() {}
неявно:
public B() : base() {}
... и если вы вообще не укажете конструктор, он будет неявно добавлен таким же образом, но ему все равно придется что-то вызывать. Например, ваш сценарий:
public class A
{
public A(int x) {}
}
public class B : A {}
приводит к ошибке компилятора:
ошибка CS7036: нет аргументов, которые соответствуют требуемому формальному параметру 'x'
of 'A.A(int)'
Однако вы можете явно указать другой вызов конструктора, например.
public B() : base(10) {} // Chain to base class constructor
или
public B() : this(10) {} // Chain to same class constructor, assuming one exists
Ответ 2
Как только вы предоставите свой собственный конструктор class A
, при создании объекта class B
автоматические вызовы не будут выполняться.
Первая строка в вашем конструкторе class B
должна быть super(paramsToClassAConstructor)
или может быть вызвана другим конструктором с class B
с помощью this()
. В этом случае второй конструктор в class B
отвечает за вызов конструктора class A
.
Ответ 3
Когда конструктор завершает выполнение - объект в допустимом начальном состоянии. Мы должны использовать объекты, которые являются действительными.
Когда мы предоставляем конструктор не по умолчанию для класса А, мы эффективно говорим - чтобы построить объект класса А, т.е. Находиться в правильном начальном состоянии - нам нужна дополнительная информация, предоставляемая параметрами.
Учитывая это, компилятор помогает не генерировать конструктор по умолчанию. Клиентский код не сможет скомпилировать (как и должно - как еще мы сделаем объект земли в правильном состоянии?) - и клиентскому программисту придется сесть и принять к сведению.
Когда вы предоставляете явный пустой конструктор - вы эффективно говорите компилятору - я знаю, что я делаю - конструктор по умолчанию, скорее всего, инициализирует поля некоторыми разумными значениями по умолчанию.
Или для содействия повторному использованию - конструктор по умолчанию может вызывать нестандартный с некоторыми значениями по умолчанию.
Подкласс знает о его суперклассе - конструктор подкласса может вызывать методы суперкласса - (некоторые часто используемые методы в подклассах). Учитывая вышеизложенное - это требует, чтобы часть суперкласса должна находиться в состоянии valid, т.е. Его конструктор был выполнен до любого его вызова метода. Это требует вызова супер-конструктора перед конструктором подкласса.
Учитывая это - вы легко сможете сконструировать свой конструктор для обеспечения правильного поведения начального состояния.