Простота — залог надежности. Edsger W. Dijkstra
Здравствуйте! Сегодня я бы хотел рассказать о наследовании. Многие новички когда начинают изучать какой-либо язык программирования сталкиваются с проблемами на своем пути. Не компилируется программа, вылетает, скобочки не хватает - это то, чего не избежать. С личного опыта хочу сказать, что мне действительно нахватало наставника, своего рода учителя как в Звездных Войнах. Что бы взял за руку, повел в правильном направлении и указал на ошибки.
Мне бы хотелось помочь ребятам подробнее разобраться и улучшить свои знания в области программирования, а именно в теме наследование в C#.
Задача: Создать базовый класс “Транспорт”. От него наследовать “Авто”, “Самолет”, “Поезд”. От класса “Авто” наследовать классы “Легковое авто”, “Грузовое авто”. От класса “Самолет” наследовать классы “Грузовой самолет” и “Пассажирский самолет”. Придумать поля для базового класса, а также добавить поля в дочерние классы, которые будут конкретно характеризовать объекты дочерних классов. Определить конструкторы, методы для заполнения полей классов (или использовать свойства). Написать метод, который выводит информацию о данном виде транспорта и его характеристиках. Использовать виртуальные методы.
И так, вы прочитали задачу. Первое, что я рекомендую сделать, это нарисовать, где вам удобно, схему проекта. Классы, поля, методы, возможно интерфейсы и т.д. В общем говоря составьте UML таблицу. Поздравляю, вы уже готовы создавать.
1) Создадим класс “Транспорт”. Должно получится следующее:
namespace ConsoleApp1
{
public abstract class Transport
{
}
}
Если вы пишете код в VS у вас будут подключены библиотеки:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Теперь давайте создадим поля, методы, конструктор по умолчанию и с параметрами.
namespace ConsoleApplication1
{
public abstract class Transport
{
public int Year { get; set; }
public int Weight { get; set; }
public string Color { get; set; }
protected Transport() { }
protected Transport(int year, int weight, string color)
{
Year = year;
Weight = weight;
Color = color;
}
public abstract void Info();
}
}
Ура! Мы написали базовый класс от которого будем наследовать дочерние классы. Условно строить машину, класс Transport это указания для ВСЕГО транспорта какой год выпуска (поле Year), вес (поле Weight), цвет (поле Color). И абстрактный метод Info, который будет выводить информацию например так: Машина -Ford Explorer. Вес - 1670 кг. Год - 2019. Цвет - черный и т.д. Еще мы описали 2 типа конструктора:
protected Transport() { }
protected Transport(int year, int weight, string color)
{
Year = year;
Weight = weight;
Color = color;
}
Конструктор это специальный блок инструкций, вызываемый при создании объекта. То есть, первый инструктор когда мы например создаем объект класса:
Transport transport = new Transport();
В таком случае мы создадим объект transport класса Transport. С параметрами по умолчанию. Что это означает? Это означает что поля Year, Weight, Color получат значения (Year = null, Weight = null, Color = null). Это сделано для того, что бы при выделении памяти в них не было мусора. Также мы можем сделать следующее:
protected Transport()
{
Year = 0;
Weight = 0;
Color = "Unknown";
}
protected Transport(int year, int weight, string color)
{
Year = year;
Weight = weight;
Color = color;
}
Тут мы явно присвоили полям какие-то свои значения.
Второй конструктор это то же самое присвоение значений, но только когда мы передаем в конструктор int year, int weight, string color:
Transport transport = new Transport(2019, 1634, "Black");
Что такое protected и public? Public — доступ открыт всем другим классам, кто видит определение данного класса. Protected — доступ открыт классам, производным от данного. То есть, производные классы получают свободный доступ к таким свойствам или метода. Все другие классы такого доступа не имеют.
Но, так как мы создали не просто класс, а абстрактный класс, нам не удастся создать его объект. Так как объект абстрактного класса создать нельзя.
2) Давайте создадим классы “Авто”, “Самолет”, “Поезд”:
using System;
namespace ConsoleApp1
{
class Train : Transport
{
public int Сarriages { get; set; }
public Train(int year, int weight, string color, int carriages) : base(year, weight, color)
{
Сarriages = carriages;
}
public override void Info()
{
Console.WriteLine("Train");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}");
Console.WriteLine($"Сarriages: {Сarriages}\n");
}
}
}
using System;
namespace ConsoleApp1
{
public class Airplane : Transport
{
public double WingLength { get; set; }
public Airplane(int year, int weight, string color, double wingLength) : base(year, weight, color)
{
WingLength = wingLength;
}
public override void Info()
{
Console.WriteLine("Airplane");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}");
Console.WriteLine($"WingLength: {WingLength:0.00}\n");
}
}
}
using System;
namespace ConsoleApp1
{
public class Car : Transport
{
public double Speed { get; set; }
public Car(int year, int weight, string color, double speed) : base(year, weight, color)
{
Speed = speed;
}
public override void Info()
{
Console.WriteLine("Car");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}");
Console.WriteLine($"Speed: {Speed:0.00}\n");
}
}
}
Мы успешно создали 3 класса. Добавили поле Speed для Car, WingLength для Airplane, Сarriages для Train, реализовали абстрактный метод класса Transport.
Так как классы очень походи давайте разберем только один, например Car.
public class Car : Transport
Этот синтаксис означает что мы публично унаследовали класс родителя Transport. Также унаследовали поля родителя:
public Car(int year, int weight, string color, double speed)
: base(year, weight, color)
Далее переопределили метод Info() также родителя. Ключевое слово override означает что мы как раз это и сделали.
public override void Info()
3) Теперь давайте создадим классы и унаследуем их от родителя Auto “Легковое авто”, “Грузовое авто”:
using System;
namespace ConsoleApp1
{
public class Truck : Car
{
public double BodyLength { get; set; }
public Truck(int year, int weight, string color, double speed, double bodyLength) : base(year, weight, color, speed)
{
BodyLength = bodyLength;
}
public override void Info()
{
Console.WriteLine("Truck");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}\n" +
$"Speed: {Speed:0.00}");
Console.WriteLine($"BodyLength: {BodyLength:0.00}\n");
}
}
}
using System;
namespace ConsoleApp1
{
public class Passenger : Car
{
public string PassengerType { get; set; }
public Passenger(int year, int weight, string color, double speed, string passengerType) : base(year, weight, color, speed)
{
PassengerType = passengerType;
}
public override void Info()
{
Console.WriteLine("Truck");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}\n" +
$"Speed: {Speed:0.00}");
Console.WriteLine($"PassengerType: {PassengerType}\n");
}
}
}
Тут ничего сложного, все по аналогии. Теперь нужно создать последние классы: “Грузовой самолет” и “Пассажирский самолет”:
using System;
namespace ConsoleApp1
{
public class PassengerPlane : Airplane
{
public int Seats { get; set; }
public PassengerPlane(int year, int weight, string color, double wingLength, int seats) : base(year, weight, color, wingLength)
{
Seats = seats;
}
public override void Info()
{
Console.WriteLine("Airplane");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}\n" +
$"WingLength: {WingLength:0.00}");
Console.WriteLine($"Seats: {Seats}\n");
}
}
}
using System;
namespace ConsoleApp1
{
public class CargoPlane : Airplane
{
public double Capacity { get; set; }
public CargoPlane(int year, int weight, string color, double wingLength, double capacity) : base(year, weight, color, wingLength)
{
Capacity = capacity;
}
public override void Info()
{
Console.WriteLine("Airplane");
Console.WriteLine($"Year: {Year}\n" +
$"Weight: {Weight}\n" +
$"Color: {Color}\n" +
$"WingLength: {WingLength:0.00}");
Console.WriteLine($"Capacity: {Capacity:0.00}\n");
}
}
}
Тут также все по антологии.
Вот и все что нужно было сделать. Теперь давайте проверим все ли работает. Создадим объекты классов:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
string[] colors = new string[] { "Blue", "Black", "Red", "Green", "Yellow" };
string[] passengerType = new string[] { "WithBody", "WithoutBody" };
Transport[] arr = new Transport[10];
for (int i = 0; i < arr.Length; i++)
{
switch (rand.Next(5))
{
case 0:
string colorPassanger = colors[rand.Next(0, colors.Length)];
string type = passengerType[rand.Next(0, passengerType.Length)];
arr[i] = new Passenger(rand.Next(18, 45), rand.Next(500), colorPassanger, rand.NextDouble() * 30 + 210, type);
break;
case 1:
string colorTruck= colors[rand.Next(0, colors.Length)];
arr[i] = new Truck(rand.Next(20, 50), rand.Next(5000), colorTruck, rand.NextDouble() * 10 + 120, rand.NextDouble() * 2 + 3);
break;
case 2:
string colorCargoPlane = colors[rand.Next(0, colors.Length)];
arr[i] = new CargoPlane(rand.Next(60, 150), rand.Next(50000), colorCargoPlane, rand.NextDouble() * 5 + 10, rand.NextDouble() * 5000 + 7000);
break;
case 3:
string colorPassengerPlane = colors[rand.Next(0, colors.Length)];
arr[i] = new PassengerPlane(rand.Next(60, 150), rand.Next(50000), colorPassengerPlane, rand.NextDouble() * 5 + 10, rand.Next(120));
break;
case 4:
string colorTrain = colors[rand.Next(0, colors.Length)];
arr[i] = new Train(rand.Next(150, 250), rand.Next(100000), colorTrain, rand.Next(10));
break;
}
}
foreach (var transport in arr)
{
transport.Info();
}
}
}
}