Energy
education

сайт для тех, кто хочет изучать энергетику

19. Полиморфизм

Слово полиморфизм означает иметь много форм. В объектно-ориентированном программировании полиморфизмом часто понимается как "один интерфейс, множество функций".

Полиморфизм может быть статическим или динамическим. В статическом полиморфизме выбор определяется во время компиляции. В динамическом полиморфизме выбор определяется во время выполнения.

Статический полиморфизм

Механизм связывания функции с объектом во время компиляции называется ранним связыванием. Он также называется статическое связывание. C# использует два механизма для реализации статического полиморфизма. Это:

  • Перегрузка метода
  • Перегрузка оператора

Перегрузка метода

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

Ниже приведен пример, в котором те же методы print() используются для печати различных типов данных:

    
using System;
namespace PolymorphismApplication
{
   class Printdata
   {
      void print(int i)
      {
         Console.WriteLine("Вывод int: {0}", i );
      }
      void print(double f)
      {
         Console.WriteLine("Вывод float: {0}" , f);
      }
      void print(string s)
      {
         Console.WriteLine("Вывод string: {0}", s);
      }
      static void Main(string[] args)
      {
         Printdata p = new Printdata();
         // вызов метода print для вывода integer
         p.print(5);
         // вызов метода print для вывода float
         p.print(500.263);
         // вызов метода print для вывода string
         p.print("Привет C#");
         Console.ReadKey();
      }
   }
}
    

Если приведенный выше код скомпилировать и выполнить, это приведет к следующему результату:

    
Вывод int: 5
Вывод float: 500.263
Вывод string: Привет C#
    

Динамический полиморфизм

C# позволяет создавать абстрактные классы, которые используются для обеспечения частичной реализации интерфейса. Реализация завершается, когда производный класс наследует от него. Абстрактные классы содержат абстрактные методы, которые осуществляются в производном классе. Производные классы имеют более специализированные функциональные возможности.

Обратите внимание на следующие правила об абстрактных классах:

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

Следующая программа демонстрирует абстрактный класс:

    
using System;
namespace PolymorphismApplication
{
   abstract class Shape
   {
      public abstract int area();
   }
   class Rectangle:  Shape
   {
      private int length;
      private int width;
      public Rectangle( int a=0, int b=0)
      {
         length = a;
         width = b;
      }
      public override int area ()
      { 
         Console.WriteLine("Площадь прямоугольника :");
         return (width * length); 
      }
   }
   class RectangleTester
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(10, 7);
         double a = r.area();
         Console.WriteLine("Площадь: {0}",a);
         Console.ReadKey();
      }
   }
}
    

Если приведенный выше код скомпилировать и выполнить, это приведет к следующему результату:

    
Площадь прямоугольника :
Площадь: 70
    

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

Динамический полиморфизм реализуется абстрактными классами и виртуальными методами.

Следующая программа демонстрирует это:

    
using System;
namespace PolymorphismApplication
{
   class Shape 
   {
      protected int width, height;
      public Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      public virtual int area()
      {
         Console.WriteLine("Площадь родительского класса :");
         return 0;
      }
   }
   class Rectangle: Shape
   {
      public Rectangle( int a=0, int b=0): base(a, b)
      {
      }
      public override int area ()
      {
         Console.WriteLine("Площадь класса Rectangle :");
         return (width * height); 
      }
   }
   class Triangle: Shape
   {
      public Triangle(int a = 0, int b = 0): base(a, b)
      {
      
      }
      public override int area()
      {
         Console.WriteLine("Площадь класса Triangle :");
         return (width * height / 2); 
      }
   }
   class Caller
   {
      public void CallArea(Shape sh)
      {
         int a;
         a = sh.area();
         Console.WriteLine("Площадь: {0}", a);
      }
   }  
   class Tester
   {
      
      static void Main(string[] args)
      {
         Caller c = new Caller();
         Rectangle r = new Rectangle(10, 7);
         Triangle t = new Triangle(10, 5);
         c.CallArea(r);
         c.CallArea(t);
         Console.ReadKey();
      }
   }
}
    

Если приведенный выше код скомпилировать и выполнить, это приведет к следующему результату:

    
Площадь класса Rectangle:
Площадь: 70
Площадь класса Triangle:
Площадь: 25