Лекция 11. Абстрактные классы

Кроме обычных классов в C# есть абстрактные классы. Абстрактный класс похож на обычный класс. Он также может иметь переменные, методы, конструкторы, свойства. Но мы не можем создать объект или экземпляр абстрактного класса. Абстрактные классы лишь предоставляют базовый функционал для классов-наследников. А производные классы уже реализуют этот функционал.

При определении абстрактных классов используется ключевое слово abstract:

abstract class Human

{

public int Length { get; set; }

public double Weight { get; set; }

}

Кроме обычных методов абстрактный класс может иметь абстрактные методы. Подобные методы определяются с помощью ключевого слова abstract и не имеют никакого функционала:

public abstract void Display();

При этом производный класс обязан переопределить и реализовать все абстрактные методы и свойства, которые имеются в базовом абстрактном классе. При переопределении в производном классе такой метод также объявляется с модификатором override. Также следует учесть, что если класс имеет хотя бы одно абстрактное свойство или метод, то он должен быть определен как абстрактный.

Абстрактные методы также, как и виртуальные, являются частью полиморфного интерфейса. Но если в случае с виртуальными методами мы говорим, что класс-наследник наследует реализацию, то в случае с абстрактными методами наследуется интерфейс, представленный этими абстрактными методами.

Зачем нужны абстрактные классы? Допустим, в нашей программе для банковского сектора мы можем определить три класса: Person, который описывает человека, Employee, который описывает сотрудника банка, и класс Client, который будет представлять клиента банка. Очевидно, что классы Employee и Client будут производными от класса Person. И так как все объекты будут представлять либо сотрудника банка, либо клиента, то напрямую мы от класса Person создавать объекты не будем. Поэтому имеет смысл сделать его абстрактным.

abstract class Person

{

public string FirstName { get; set; }

public string LastName {get; set; }

 

public Person(string lName, string fName)

{

   FirstName = fName;

   LastName = lName;

}

 

public abstract void Display();

}

 

class Client: Person

{

public string Bank { get; set; }

 

public Client(string lName, string fName, string comp)

  : base(fName, lName)

{

   Bank = comp;

}

 

public override void Display()

{

   Console.WriteLine(FirstName + " " + LastName + " имеет счет в банке " + Bank);

}

}

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

// абстрактный класс фигуры

abstract class Figure

{

float x; // x-координата точки

float y; // y-координата точки

 

public Figure(float x, float y)

{

   this.x=x;

   this.y=y;

}

 

// абстрактный метод для получения периметра

public abstract float Perimeter();

// абстрактный метод для получения площади

public abstract float Area();

}

// производный класс прямоугольника

class Rectangle: Figure

{

public float Width { get; set; }

public float Height { get; set; }

 

// конструктор с обращением к конструктору класса Figure

public Rectangle(float x, float y, float width, float height)

  : base(x, y)

{

   this.Width = width;

   this.Height = height;

}

// переопределение получения периметра

public override float Perimeter()

{

   return Width * 2 + Height * 2;

}

// переопрелеление получения площади

public override float Area()

{

   return Width * Height;

}

}

 

Лекция 12. Класс System.Object

В начале всей цепочки наследования классов находится класс System.Object. Все остальные классы, даже те, которые мы добавляем в свой проект, а также базовые типы, такие как System.Int32, являются неявно производными от класса Object. Даже если мы не указываем класс Object в качестве базового, по умолчанию неявно класс Object все равно стоит на вершине иерархии наследования. Поэтому все типы и классы могут реализовать те методы, которые определены в классе Класс System.Object. Рассмотрим эти методы.

ToString

Метод ToString служит для получения строкового представления данного объекта. Для базовых типов просто будет выводиться их строковое значение:

int i = 5;

Console.WriteLine(i.ToString()); // выведет число 5

 

double d = 3.5;

Console.WriteLine(d.ToString()); // выведет число 3,5

Для классов же этот метод выводит полное название класса с указанием пространства имен, в котором определен этот класс. И мы можем переопределить данный метод. Посмотрим на примере:

class Human

{

public string Name { get; set; }

 

public override string ToString()

{

   return Name;

}

}

 

class Animal { }

 

class Program

{

static void Main(string[] args)

{

 

   Human human = new Human();

   human.Name = "Том";

   Console.WriteLine(human.ToString()); // выведет имя Том

 

   Animal anim = new Animal();

   Console.WriteLine(anim.ToString()); // выведет название класса Animal

 

   Console.ReadLine();

}

}

Для класса Human метод ToString() переопределен с помощью ключевого слова override и выводит значение свойства Name. А для класса Animal срабатывает стандартная реализация этого метода, которая выводит просто название класса.

Кстати в данном случае мы могли задействовать обе реализации. Например, что будет, если для объекта human не будет установлено имя? Тогда будет выведена пустая строка. Однако мы можем изменить реализацию метода ToString, чтобы в подобном случае она выводила имя класса:

class Human

{

public string Name { get; set; }

 

public override string ToString()

{

   if (String.IsNullOrEmpty(Name)) // проверка на наличие значения строки

   {

       return base.ToString();

   }

   else

   {

       return Name;

   }

}

}

Метод GetHashCode

Метод GetHashCode позволяет возвратить некоторое числовое значение, которое будет соответствовать данному объекту или его хэш-код. По данному числу, например, можно сравнивать объекты. Можно определять самые разные алгоритмы генерации подобного числа или взять реализаци базового типа:

class Human

{

public string Name { get; set; }

 

public override int GetHashCode()

{

   return base.GetHashCode();

}

}

Получение типа объекта и метод GetType

Метод GetType позволяет получить тип данного объекта:

Animal anim = new Animal();

Console.WriteLine(anim.GetType());

Например, у нас есть иерархия классов, где классы Employee и Client наследуются от общего класса Person. У нас есть несколько объектов класса Person, и мы хотим обратиться только ко всем клиентам. В этом случае мы можем проверить их тип:

Person[] persons = new Person[]{new Client("Tom", "Johnes", "SberBank", 200, 20),

   new Employee("Bill", "Gates", "Microsoft")};

foreach (Person p in persons)

{

if (p.GetType() == typeof(Client))

{

   Console.WriteLine("Это объект класса Client");

}

}

С помощью ключевого слова typeof мы получаем тип класса и сравниваем его с типом объекта. И если этот объект представляет тип Client, то выполняем определенные действия.

Метод Equals

Метод Equals позволяет сравнить два объекта на равенство:

class Human

{

public string Name { get; set; }

 

public override bool Equals(object obj)

{

   if (obj.GetType()!= this.GetType()) return false;

 

   Human human2 = (Human)obj;

   return (this.Name == human2.Name);

}

}

Метод Equals принимает в качестве параметр объект любого типа, который мы затем приводим к текущему, если они являются объектами одного класса. Затем сравниваем по именам. Если имена равны, возвращаем true, что будет говорить, что объекты равны.

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: