C# полиморфизм

Полиморфизм — это способность одного и того же поведения иметь несколько различных форм или проявлений.

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

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

В C# каждый тип является полиморфным, поскольку все типы, включая пользовательские типы, наследуются от Object.

Полиморфизм означает один и тот же интерфейс, использующий разные экземпляры для выполнения разных операций, как показано на рисунке:

В реальной жизни, например, действие нажатия клавиши F1:

  • Если вы сейчас в интерфейсе Flash, всплывает документ справки AS 3;
  • Если вы сейчас в Word, всплывает справка Word;
  • Если вы работаете в Windows, всплывает "Справка и поддержка Windows".

Одно и то же событие, происходящее с разными объектами, даст разные результаты.

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

Во время компиляции механизм, связывающий функции и объекты, называется ранним связыванием, также известным как статическое связывание. C# предоставляет две технологии для реализации статического полиморфизма. Это:

  • Перегрузка функций
  • Перегрузка операторов

Перегрузка операторов будет рассмотрена в следующей главе; далее мы рассмотрим перегрузку функций.


Перегрузка функций

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

В следующем примере демонстрируются несколько одинаковых функцийAdd(), используемых для выполнения сложения с разным количеством параметров:

Пример

using System;
namespace PolymorphismApplication
{
    public class TestData  
    {  
        public int Add(int a, int b, int c)  
        {  
            return a + b + c;  
        }  
        public int Add(int a, int b)  
        {  
            return a + b;  
        }  
    }  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            TestData dataClass = new TestData();
            int add1 = dataClass.Add(1, 2);  
            int add2 = dataClass.Add(1, 2, 3);

            Console.WriteLine("add1 :" + add1);
            Console.WriteLine("add2 :" + add2);  
        }  
    }  
}

Следующий пример демонстрирует несколько одноимённых функцийprint(), используемых для вывода различных типов данных:

Пример

using System;
namespace PolymorphismApplication
{
   class Printdata
   {
      void print(int i)
      {
         Console.WriteLine("Вывод целого числа: {0}", i );
      }

      void print(double f)
      {
         Console.WriteLine("Вывод типа с плавающей точкой: {0}" , f);
      }

      void print(string s)
      {
         Console.WriteLine("Вывод строки: {0}", s);
      }
      static void Main(string[] args)
      {
         Printdata p = new Printdata();
         // Вызов print для вывода целого числа
         p.print(1);
         // Вызовите print для вывода числа с плавающей запятой
         p.print(1.23);
         // Вызовите print для вывода строки
         p.print("Hello Example");
         Console.ReadKey();
      }
   }
}

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

输出整型: 1
输出浮点型: 1.23
输出字符串: Hello Example

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

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

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

  • Нельзя создать экземпляр абстрактного класса.
  • Нельзя объявить абстрактный метод вне абстрактного класса.
  • Разместив ключевое слово перед определением классаsealed, класс можно объявить какsealed class. Когда класс объявлен какsealedЕсли класс sealed, он не может быть унаследован. Абстрактный класс нельзя объявить как sealed.

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

Пример

using System;
namespace PolymorphismApplication
{
   abstract class Shape
   {
       abstract public 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(Площадь класса Rectangle:);
         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();
      }
   }
}

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

Rectangle 类的面积:
面积: 70

Когда функция, определённая в классе, должна быть реализована в классе-наследнике, можно использоватьвиртуальный метод。

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

Виртуальные методы могут иметь разные реализации в разных классах-наследниках.

Вызов виртуального метода происходит во время выполнения.

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

В следующем примере создается базовый класс Shape и производные классы Circle, Rectangle, Triangle. Класс Shape предоставляет виртуальный метод с именем Draw, который переопределяется в каждом производном классе для рисования заданной фигуры для этого класса.

Пример

using System;
using System.Collections.Generic;

public class Shape
{
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }
   
    // Виртуальный метод
    public virtual void Draw()
    {
        Console.WriteLine("Выполнить задачу рисования базового класса");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Нарисуйте круг");
        base.Draw();
    }
}
class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Нарисуйте прямоугольник");
        base.Draw();
    }
}
class Triangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Нарисуйте треугольник");
        base.Draw();
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Создайте объект List<Shape> и добавьте в него Circle, Triangle и Rectangle.
        var shapes = new List<Shape>
        {
            new Rectangle(),
            new Triangle(),
            new Circle()
        };

        // Используйте цикл foreach, чтобы перебрать производные классы этого списка, и вызвать метод Draw для каждого объекта Shape
        foreach (var shape in shapes)
        {
            shape.Draw();
        }

        Console.WriteLine("Нажмите любую клавишу для выхода.");
        Console.ReadKey();
    }

}

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

Draw a rectangle
Execute the base class drawing task
Draw a triangle
Execute the base class drawing task
Draw a circle
Execute the base class drawing task
Press any key to exit.

Следующая программа демонстрирует вычисление площади различных фигур с использованием виртуального метода area():

Пример

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
Другие расширения