2012-01-24 2 views
1

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

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

Я создаю свой основной класс, который является животным с некоторыми родовыми полями, применимыми ко всем животным, позволяет назвать имя, возраст и виды.

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

Теперь я хочу создать новое животное, которое является кошкой, im берёт данные из нескольких списков, поэтому мне нужен конструктор, который принимает эти параметры, и это то, что я не получаю, мне нужно объявить их в каждом дочернем класс также?

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

+1

Вы запутались в своем примере. Например, только у кошек есть зубы или все животные? Позволяет ради аргумента сказать, что все животные (в основном правильное утверждение) - то не должны ли зубы быть частью вашего базового класса? –

+0

Ну, это был всего лишь пример, у меня будет несколько категорий и видов, и у каждого вида будет уникальное поле, но затем изменим это на усы: p. – Gvs

+0

@ user1083543: Кажется, что это какое-то задание домашней работы/класса. По этой причине, может быть много преимуществ Наследования, что это конкретное задание не будет заставлять вас использовать рычаги. Но цель задания - познакомить вас с наследованием, чтобы, когда вам это действительно нужно, вы можете использовать его. – xbonez

ответ

4

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

Без наследования

class Cat 
{ 
    float height; 
    float weight; 
    float energy; 
    string breed; 

    int somethingSpecificToCat; 

    public Cat() 
    { 
     //your constructor. initialize all fields 
    } 

    public Eat() 
    { 
     energy++; 
     weight++; 
    } 

    public Attack() 
    { 
     energy--; 
     weight--; 
    } 

} 

class Dog 
{ 
    float height; 
    float weight; 
    float energy; 
    string breed; 

    int somethingSpecificToDog; 

    public Dog() 
    { 
     //your constructor. initialize all fields 
    } 

    public Eat() 
    { 
     energy++; 
     weight++; 
    } 

    public Attack() 
    { 
     energy--; 
     weight--; 
    } 

} 

с наследованием

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

abstract class Animal 
{ 
    float height; 
    float weight; 
    float energy; 
    string breed; 

    public Eat() 
    { 
     energy++; 
     weight++; 
    } 

    public Attack() 
    { 
     energy--; 
     weight--; 
    } 
} 
class Cat : Animal 
{ 
    int somethingSpecificToCat; 

    public Cat() 
    { 
     //your constructor. initialize all fields 
    } 
} 

class Dog : Animal 
{ 
    int somethingSpecificToDog; 

    public Dog() 
    { 
     //your constructor. initialize all fields 
    } 
} 

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

Пример

abstract class Animal 
{ 
    static int sID = 0; 

    float height; 
    float weight; 
    int id; 

    public Animal() 
    { 
     id = ++sID; 
    } 
} 

Теперь, когда вы делаете;

Dog lassie = new Dog(); //gets ID = 1 
Cat garfield = new Cat(); // gets ID = 2 

Если вы хотите получить список всех животных в вашей 'фермы',

без наследования

List<Cat> cats = new List<Cat>(); //list of all cats 
List<Dog> dogs = new List<Dog>(); //list of all dogs 
...etc 

С наследованием

List<Animal> animals = new List<Animal>(); //maintain a single list with all animals 
animals.Add(lassie as Animal); 
animals.Add(garfield as Animal); 

Таким образом, если вы хотите t о если у вас есть животное под названием Pluto, вам просто нужно перебирать один список (животных), а не несколько списков (кошки, собаки, свиньи и т.д.)

EDIT в ответ на ваш комментарий

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

abstract class Animal 
{ 
    float height; 
    float weight; 
    float energy; 
    string breed; 

    public Eat() 
    { 
     energy++; 
     weight++; 
    } 

    public Attack() 
    { 
     energy--; 
     weight--; 
    } 
} 
class Cat : Animal 
{ 
    int somethingSpecificToCat; 

    public Cat() 
    { 
     //your constructor. initialize all fields 
    } 
} 

class Dog : Animal 
{ 
    int somethingSpecificToDog; 

    public Dog() 
    { 
     //your constructor. initialize all fields 
    } 
} 

Cat garfield = new Cat(); 
garfield.height = 24.5; 
garfield.weight = 999; //he's a fat cat 
//as you can see, you just instantiate the object garfield 
//and instantly have access to all members of Animal 

Animal jerry = new Animal(); //throws error 
//you cannot create an object of type Animal 
//since Animal is an abstract class. In this example 
//the right way would be to create a class Mouse deriving from animal and then doing 

Mouse jerry = new Mouse(); 

Edit на ваш комментарий

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

List<Animal> animals = new List<Animal>(); 
animals.Add(garfield as Animal); 
animals.Add(lassie as Animal); 

//if you do not cast, you cannot access fields that were specific to the derived class. 
Console.WriteLine(animals[0].height); //this is valid. Prints Garfield's height 
Console.WriteLine(animals[0].somethingSpecificToCat); //invalid since you haven't casted 
Console.WriteLine((animals[0] as Cat).somethingSpecificToCat); //now it is valid 

//if you want to do it in a loop 

foreach(Animal animal in animals) 
{ 
    //GetType() returns the derived class that the particular animal was casted FROM earlier 

    if(animal is Cat) 
    { 
     //the animal is a cat 
     Cat garfield = animal as Cat; 
     garfield.height; 
     garfield.somethingSpecificToCat; 
    } 
    else if (animal is Dog) 
    { 
     //animal is a dog 
     Dog lassie = animal as Dog; 
     lassie.height; 
     lassie.somethingSpecificToDog; 
    } 
} 
+0

Хорошо для следующего вопроса: p. Мой класс животных должен получать свои значения из моей формы, но как я могу это назвать? Сначала создайте новое животное с параметрами, затем позвоните, чтобы сделать нового кота после? – Gvs

+0

@ user1083543: Вам не нужно создавать экземпляр животного. Вы просто создаете кошку или собаку. На самом деле, если ваше животное всегда будет определенным типом животного, а не просто общим животным, вы должны использовать ключевое слово 'abstract' в базовом классе Animal. Это гарантирует, что вы не можете создать объект типа «Animal». См. Редактирование, которое я делаю, чтобы ответить, чтобы лучше объяснить. – xbonez

+0

Спасибо миллион за то, что он объяснил это так ясно, очень оценил. – Gvs

0

Наследование не касается только конструкторов. Например, в вашем базовом классе Animal вы можете объявить метод Eat (что-то) или Grow(), который будет равен для всех преемников.

BTW, проблема заключается в вызове конструктора по умолчанию Cat() с тремя параметрами (так называем базовый конструктор Animal), а затем с указанием зубов путем установки соответствующего поля или свойства.

+0

Эффективное создание наследования полезно только в том случае, если у меня есть метод, который применяется ко всем животным, например, говорить()? – Gvs

+0

Да, конечно. Но это самый распространенный случай. Вы также можете найти эту статью полезной: http://msdn.microsoft.com/en-us/library/27db6csx%28v=vs.71%29.aspx –

1

Вы должны сообщить застройщик принять аргументы (если вы wan't требовать от них), но вам не нужно снова реализовать свойства:

public class Animal 
{ 
    public string Name { get; set; } 

    public Animal(string Name) 
    { 
     Name = name; 
    } 
} 

public class Cat : Animal 
{ 
    public int Teeth { get; set; } 

    public Cat(string name, int teeth) 
    { 
     Name = name; //<-- got from base 
     Teeth = teeth; //<-- defined localy 
    } 
    //or do this 
    public Cat(string name, int teeth) : base(name) 
    { 
     Teeth = teeth; 
    } 
} 

Вы также можете сделать следующее:

Cat cat = new Cat("cat", 12); 
Animal kitty = cat as Animal; 

Что имеет смысл, например, если вы хотите получить список как List<Animal> вы можете добавить Cat -instance:

List<Animal> animals = new List<Animal>(); 
animals.Add(new Animal("Coco")); 
animals.Add(cat); 

foreach(Animal animal in animals) 
{ 
    Console.WriteLine(String.Format("Name: {0}", animal.Name)); 
    if(animal is Cat) 
    { 
     Console.WriteLine(String.Format("{0} is a Cat with {1} teeth.", animal.Name 
      (animal as Cat).Teeth)); 
    } 
    Console.WriteLine("============"); 
} 

, которые будут выводить:

Name: Coco 
============ 
Name: cat 
cat is a Cat with 12 teeth. 
============ 
0

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

List<Animal> animals = new List<Animal>(); 

animals.Add(new Cat()); 
animals.Add(new Dog()); 

и т.д. и т.п.

1

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

1

Выгода заключается в том, что вам не нужно декларировать имя возрастных видов у всех видов животных. Вы получаете их заранее подготовленные для вас. Еще один замечательный момент, который позволяет вам наследовать. Допустим, вы хотите иметь множество животных. Поэтому вы вводите что-то вроде. Arraylist arr = и т. Д. И т. Д. ... , но это будет содержать только объекты типа кошки. Поэтому вместо этого вы можете сделать что-то вроде Arraylist, и это будет содержать все виды животных, кошек и собак. В основном переменная базового класса может указывать на переменную производного класса. Это очень удобно в большинстве сценариев, поскольку все усложняется.

+0

Посмотрите, что я не получу, возможно, это я, это паршивый но важно, что это задача, которую я получил: я получаю имя, возраст и вид из текстовых полей или списков, а затем мне нужно «сделать» животное. Допустим, я выбрал кошку как фигуру, тогда я хочу создать животное с уникальными данными для кошки. В следующий раз, когда я добавлю рыбу с ее уникальными данными и так далее, единственное, что когда-либо будет отличаться, - это уникальные данные обо всех видах, которые будут содержаться в подклассе животного базового класса. – Gvs

+0

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

0

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

например (кража кода chrfin в):

public class Animal 
{ 
    public string Name { get; set; } 
} 

public class Cat : Animal 
{ 
    public int Teeth { get; set; } 

    public Cat(string name, int teeth) : Base(name) //pass name to base constructor 
    { 
     Teeth = teeth; 
    } 
} 
+0

Просто добавил то же самое к моему ответу (не читая сначала): D – ChrFin

0

Вы полностью overthinking это.

Какую цель выполняет класс животных?

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

0

Да, вы должны создать конструктор, но это не делает наследование бессмысленно, хотя на самом деле является хорошей практика предпочитают композиции над наследованием, то есть обычно (не всегда) лучше иметь кошку, которая имеет свойство HAS-A, чем кошка, которая является животным IS-A.

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

Кроме наследования вы можете использовать полиморфизм, что у вас есть этот класс (псевдо-код)

public abstract class Animal() 
{ 
    //Some atributes 

    //Methods 

    makeSound(); 
} 

то есть

public class Cat extends Animal 
{ 
    makeSound() 
    { 
    System.out.println("meow"); 
    } 
} 

Тогда говорят, вы расширяете животное для собаки также:

public class Dog extends Animal 
{ 
    makeSound() 
    { 
     System.out.println("woof") 
    } 
} 

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

List<Animal> animals = new ArrayList<Animal>(); 
animals.add(cat); 
animals.add(dog); 

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

for (Animals animal : animals) 
{ 
    animal.makeSound(); 
} 

И напечатает для «мяуканье кошки "

и для собаки

"Гав"

0

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

class Animal 
{ 
    public string Name { get; set; } 

    public Animal(string name) 
    { 
     Name = name; 
    } 

} 

class Cat : Animal 
{ 
    // Put cat-only properties here... 

    public Cat(string name) : base(name) 
    { 
     // Set cat-specific properties here... 
    } 
} 

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

0

Вы сбиты с толку, потому что думаете только о конструкторах. Факт, как объясняется в msdn, «Конструкторы и деструкторы не наследуются». Поэтому, когда вы наследуете вас классом, конструкторы базового класса не относятся к производному классу. Производный класс должен упомянуть свой собственный набор конструкторов/деструкторов. Чтобы понять, почему это так, вы можете посмотреть здесь: Why are constructors not inherited?.

Теперь, на ваш вопрос, да, вы должны добавить конструктор в свой класс cat, чтобы принять все четыре параметра. Но вам не нужно снова вводить эти 3 поля в свой класс cat. Все общедоступные защищенные и внутренние поля и методы вашего класса животных по-прежнему доступны для вашего класса cat, и вам не нужно переопределять их в вашем производном классе. Так ваш базовый класс обслуживает ваш производный класс.

+0

Но как это работает, когда параметры для класса животных проходят из формы? Я хочу создать кошку, которая должна наследовать поля от животных, но класс животных еще не имеет значений, поскольку они передаются из формы?Итак, как класс животных знает, какие ценности в моей форме, если я хочу создать кошку, а не животное? – Gvs

+0

В наследовании родительский класс не будет знать о производном классе. Поэтому класс животных не будет знать о классе кошки или собаки. Также вы не можете ожидать, что C# решит, какой класс он должен создать. На основе значений, выбранных в форме, вы должны написать программу, которая создаст объект соответствующего класса. Затем присвойте значения из формы соответствующим полям вашего объекта. Это должно быть явно сделано вами. – Rakesh

Смежные вопросы