0

Я немного упростил свой код чтоб мне могли обьяснить. Короче есть базовый клас Vegetable, и также Tomato, который наследуют базовый. Я создаю список типа Vegetable и добавляю туда обьекты типа Tomato, указывая в каждом количество помидорок (переменная quantity). Проблема заключаеться в конце, когда я пытаюсь вывести весь список обьектов с их соответствующим количеством. При дебаге увидел, что обьекты имеют 2 переменные:

quantity (Vegetable) [int]: 0 //это то, что выводит в конце

quantity [int]: 2 //тут как раз число, котороя я вводил

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

class Vegetable
{
   public int quantity;
}
class Tomato : Vegetable
{
   new public int quantity { get; set; }
}

class Program13 { static void Main(string[] args) { List<Vegetable> vegetableList = new List<Vegetable>();

Tomato tomato1 = new Tomato(); Console.WriteLine("Write quantity of tomatoes1"); vegetableList.Add(tomato1); tomato1.quantity = Convert.ToInt32(Console.ReadLine());

Tomato tomato2 = new Tomato(); Console.WriteLine("Write quantity of tomatoes2"); vegetableList.Add(tomato2); tomato2.quantity = Convert.ToInt32(Console.ReadLine());

Console.WriteLine("Salad contains:"); foreach (var obj in vegetableList) { Console.WriteLine($"{obj.quantity} {obj.GetType()}"); }

} }

Выводит это: Salad contains:

0 Tomato
0 Tomato

  • Понял что дело при создании обьектов. Типо надо Vegetable tomato1 = new Tomato() а я создавал Tomato tomato1 = new Tomato() Но я не вижу разницы. Основы ООП изучал в c++, поэтому с новыми реалиями c# еще сложно. Обьясните пожалуйста почему так – Semechko Mar 15 '23 at 01:21

1 Answers1

3

вы используете "сокрытие", то есть ваше свойство new public int quantity { get; set; } как бы скрывает поле public int quantity; (см про оператор new). При сокрытии по сути оба quantity остаются, какой из них будет вызван зависит от типа переменной.

То есть вот тут myObject.quantity - если переменная myObject имеет тип Vegetable - то будет из него использоваться поле, если же myObject имеет тип Tomato - то оттуда.

Вообще это редко когда имеет смысл так делать. Обычно, если надо переопределить что то в производном классе, то в базовом это чтото (свойство или метод, например) объявляют виртуальными (virtual) и в производных классах уже перегружают (override). В этом случае тип переменной не важен, всегда будет вызываться код производного класса.

Пример

class Vegetable
{
    public virtual int quantity { get; set; }
}
class Tomato : Vegetable
{
    public override int quantity { get; set; }
}

Проверка

List<Vegetable> vegetableList = new List<Vegetable>();

Tomato tomato1 = new Tomato(); tomato1.quantity = 10;
vegetableList.Add(tomato1);

Console.WriteLine("Salad contains:"); foreach (var obj in vegetableList) { Console.WriteLine($"{obj.quantity} {obj.GetType().Name}"); }

Вывод

Salad contains:
10 Tomato

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

tym32167
  • 32,857
  • Спасибо! С переопределением разобрался, но все еще не понимаю смысл строки Vegetable tomato1 = new Tomato() Я впринципе не понимаю эту строку. Увидел как другие обьявляют переменные при наследовании и решил попробовать - сработало, но почему не понимаю. – Semechko Mar 15 '23 at 02:04
  • 1
    Это называется upcast, подробнее читайте тут – tym32167 Mar 15 '23 at 02:25