Лекция 10. Полиморфизм. Переопределение методов

Полиморфизм является третьим ключевым аспектом объектно-ориентированного программирования и предполагает способность к изменению функционала, унаследованного от базового класса. Полиморфизм предполагает определение полиморфного интерфейса в базовом классе - набор членов класса, которые могут быть переопределены в классе-наследнике. Методы, которые мы хотим сделать доступными для переопределения, в базовом классе помечается модификатором virtual. Такие методы называют виртуальными. Они и представляют полиморфный интерфейс (также частью полиморфного интерфейса могут быть абстрактные члены класса, о которых рассказывается в следующей теме).

При определении класса-наследника и наследовании методов базового класса мы можем выбрать одну из следующих стратегий:

· Обычное наследование всех членов базового класса в классе-наследнике

· Переопределение членов базового класса в классе-наследнике

· Скрытие членов базового класса в классе-наследнике

Первая стратегия довольно проста. Допустим, есть следующая пара классов Person и Employee:

class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

           public Person(string lName, string fName)

{

   FirstName = fName;

   LastName = lName;

}

               

public virtual void Display()

{

   Console.WriteLine(FirstName + " " + LastName);

}

}

 

class Employee: Person

{

public string Company { get; set; }

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

                                         :base(fName, lName)

{

   Company = comp;

}

}

В базовом классе Person метод Display() определен с модификаторами virtual, поэтому данный метод может быть переопределен. Но класс Employee наследует его как есть:

class Program

{

static void Main(string[] args)

{

   Person p1 = new Person("Bill", "Gates");

   p1.Display(); // вызов метода Display из класса Person

 

   Person p2 = new Employee("Tom", "Johns", "UnitBank");

   p2.Display(); // вызов метода Display из класса Person

 

   Employee p3 = new Employee("Sam", "Toms", "CreditBank");

   p3.Display(); // вызов метода Display из класса Person

   Console.Read();

}

}

Консольный вывод:

Bill GatesTom JohnsSam Toms

Вторая стратегия - переопределение методов базового класса в классе-наследнике предполагает использование ключевого слова override:

class Employee: Person

{

public string Company { get; set; }

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

                                         :base(fName, lName)

{

   Company = comp;

}

               

public override void Display()

{

   Console.WriteLine(FirstName + " " + LastName + " работает в компании "+ Company);

}

}

Класс Person остается тем же, в нем так же метод Display объявляется как виртуальный. В этом случае поведение объекта Employee изменится:

Person p1 = new Person("Bill", "Gates");

p1.Display(); // вызов метода Display из класса Person

 

Person p2 = new Employee("Tom", "Johns", "UnitBank");

p2.Display(); // вызов метода Display из класса Employee

 

Employee p3 = new Employee("Sam", "Toms", "CreditBank");

p3.Display(); // вызов метода Display из класса Employee

Консольный вывод:

Bill GatesTom Johns работает в компании UnitBankSam Toms работает в компании CreditBank

При третьей стратегии можно просто определить в классе-наследнике метод с тем же именем, добавив в его определение ключевое слово new:

class Employee: Person

{

public string Company { get; set; }

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

                                         :base(fName, lName)

{

   Company = comp;

}

               

public new void Display()

{

   Console.WriteLine(FirstName + " " + LastName + " работает в компании "+ Company);

}

}

В этом случае метод Display() в Employee скрывает метод Display() из класса Person. Чтобы явно скрыть метод из базового класса, используется ключевое слово new, хотя в принципе оно необязательно, по умолчанию система это делает неявно.

Использование в программе:

Person p1 = new Person("Bill", "Gates");

p1.Display(); // вызов метода Display из класса Person

 

Person p2 = new Employee("Tom", "Johns", "UnitBank");

p2.Display(); // вызов метода Display из класса Person

 

Employee p3 = new Employee("Sam", "Toms", "CreditBank");

p3.Display(); // вызов метода Display из класса Employee

Консольный вывод:

Bill GatesTom JohnsSam Toms работает в компании CreditBank

Обратите внимание на различия во втором случае (p2.Display()) при разных стратегиях.

Ключевое слово base

Кроме конструкторов, мы можем обратиться с помощью ключевого слова base к другим членам базового класса. В нашем случае вызов base.Display(); будет обращением к методу Display() в классе Person:

class Employee: Person

{

public string Company { get; set; }

 

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

                                         :base(fName, lName)

{

   Company = comp;

}

 

public override void Display()

{

   base.Display();

   Console.WriteLine("Место работы: " + Company);

}

}

Запрет переопределения методов

Также можно запретить переопределение методов и свойств. В этом случае их надо объявлять с модификатором sealed:

class Employee: Person

{

public string Company { get; set; }

 

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

                                         :base(fName, lName)

{

   Company = comp;

}

 

public override sealed void Display()

{

   base.Display();

   Console.WriteLine("Место работы: " + Company);

}

}

При создании методов с модификатором sealed надо учитывать, что sealed применяется в паре с override, то есть только в переопределяемых методах.

И в этом случае мы не сможем переопределить метод Display в классе, унаследованном от Employee.

 


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



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