Конструктор - это метод, который, как вы можете быть уверены, вызывается при построении экземпляра класса, потому что поведение принудительное.Следовательно, вы можете поместить код в конструкцию, чтобы гарантировать, что класс готов к использованию
В случае суперкласса, хотя вы не можете создать его напрямую, ваши дочерние классы могут получить некоторые параметры (или вы можете жестко закодироватьих) и передайте их родительскому конструктору для действия, а не для выполнения самих действий.
В вашем случае с животным предположим, что у животного есть несколько ног.Все животные делают, так что это свойство Animal, а не Dog.Ваш конструктор собак может установить количество ног, если у него есть доступ к нему, или он может вызвать базовый конструктор, передавая количество ног, если у него его нет.
Объявляя Aninal иметь конструктор, который требует количество ног, вы никогда не забудете создать дочерний класс, в котором пропущено количество ног, потому что вы не сможете вызвать базовый конструктор.без его предоставления
class Animal{
Animal(int numberOfLegs){}
}
class Dog:Animal{
Dog(string breed): base(4) {} //call base constructor
}
class Cat:Animal{} //doesn't work; error "no argument is given that corresponds to formal parameter 'numberOfLegs'"
Если вы не предоставите конструктор в конкретном классе, компилятор автоматически вставит для вас пустой параметр без параметров, который ничего не делает, кроме вызова базового параметра без параметров.Если вы предоставите конструктор, он не создаст пустой.Это то, что приводит к ошибке «никакой аргумент не соответствует ...» - компилятор автоматически вставил конструктор в Cat, который вызывает Animal (), но не имеет параметра без параметров, и компилятор не будет угадывать, что intпредоставить для количества элементов.
Следовательно, поскольку у Animal есть конструктор, который требует несколько ветвей, мы вынуждены каким-то образом предоставить ему значение (мы могли бы принять параметр в конструкторе Dog, чтобы внешний код мог объявить количество ветвей)) - по сути, мы не можем создать любой подкласс Animal, если не создадим конструктор в подклассе, который вызывает base(some_int_here)
.
Если животное не сможет работать без установленного количества ног, этот механизм гарантирует, что установлено количество ног (для краткости я не показывал установочный код, который присваивает количество ног внутри в Animal)
Таким образом, да, у суперклассов должны быть конструкторы - у всех классов должны быть (и есть) конструкторы (это «закон»).Иногда конструкторы пустые, а иногда они что-то делают
Вы также сказали, что не видите, как мы построим просто простое животное, а не конкретную собаку, кошку и т. Д.
Вымы правы, мы можем этого не делать ... но прелесть ОО состоит в том, что мы можем использовать Animal для общего обозначения всех его детей.Мы можем создать множество животных и поместить туда 10 разных животных и использовать их общие свойства и методы, не зная и не заботясь о том, что они из себя представляют.В реальном мире мы относимся к вещам генетически все время, используя их общие свойства.Я никогда не водил Мерседес, но он, вероятно, работает в основном так же, как мой Форд, педали в том же месте и делают то же самое, когда нажимают.Мы не всегда заботимся о конкретных деталях каждого объекта в нашей жизни, что у брода есть тросовая муфта, а у merc гидравлическая;это просто работает так же, когда мы нажимаем на педаль.Точно так же наш массив Животных, мы можем просто пройти его и сложить количество ног без необходимости знать каждый тип животного
Animal[] x = new Animal[10]();
x[0] = new Dog();
...
Это не создает животное, оно создает собаку, но животноеКонструктор вызывается как часть процесса.В конце этого мы можем сложить ноги, получив доступ к NumberOfLegs животного, не говоря «если элемент массива - собака, тогда добавьте еще 4, если ...»
Именно поэтому базовые классы имеют атрибуты, итакже конструкторы (потому что они тоже могут нуждаться в настройке)