سی شارپ - چند ریختی

polymorphism به معنای داشتن چند شکل یا فرم می باشد. در الگوی برنامه نویسی شی گرا، polymorphism اغلب به عنوان یک اینترفیس، چند تابع نشان داده می شود.

Polymorphism می تواند استاتیک یا داینامیک باشد. در نوع استاتیک، پاسخ یک تابع در زمان اجرا تعیین می شود، ولی در نوع داینامیک یا پویا ، در زمان اجرا مشخص می شود

چند ریختی استاتیک

مکانیزم لینک کردن یک تابع به یک شی در زمان کامپایل ، اتصال اولیه و یا اتصال استاتیک نامیده می شود، سی شارپ دو تکنیک برای اجرای static polymorphism ارائه می دهد که عبارتند از

  • Function overloading
  • Operator overloading

در فصل بعدی operator overloading توضیح داده خواهد شد

Function Overloading

شما می توانید چند تعریف ازیک تابع در هر بخش داشته باشید. هر تعریف از این تابع از طریق نوع ویا تعداد آرگومان های ورودی آن با تعریف دیگر متفاوت است، توجه داشته باشید که . overload های مختلف از طریق تغییر نوع برگشتی تابع نمی تواند انجام شود

در زیر مثالی را می بینید که از یک تابع print() برای چاپ انواع مختلف داده استفاده می شود.

using System;
namespace PolymorphismApplication
{
   class Printdata
   {
      void print(int i)
      {
         Console.WriteLine("Printing int: {0}", i );
      }

      void print(double f)
      {
         Console.WriteLine("Printing float: {0}" , f);
      }

      void print(string s)
      {
         Console.WriteLine("Printing string: {0}", s);
      }
      static void Main(string[] args)
      {
         Printdata p = new Printdata();
         
         // Call print to print integer
         p.print(5);
         
         // Call print to print float
         p.print(500.263);
         
         // Call print to print string
         p.print("Hello C++");
         Console.ReadKey();
      }
   }
}

خروجی دستورات بالا به صورت زیر است:

Printing int: 5
Printing float: 500.263
Printing string: Hello C++

چند ریختی داینامیک یا پویا

برنامه ی سی شارپ به شما اجازه می دهد تا کلاس های انتزاعی ایجاد کنید که برای پیاده سازی یک اینترفیس ، کلاس های پارشیال (partial) ایجاد می کند. پیاده ساز ی یا ایمپلمنتیشن ،زمانی کامل می شود که یک کلاس مشتق شده از آن اینترفیس ارث بری کند. کلاس های انتزاعی یا abstract دارای متد های abstract می باشند که به وسیله ی کلاس مشتق پیاده سازی می شوند. کلاس های مشتق پیاده سازی های بیشتری دارند.

قوانین کلاس انتزاعی یا absract در زیر آورده شده است:

  • شما نمی توانید نمونه ای از کلاس انتزاعی یا ابسترکت ایجاد کنید.
  • نمی توانید یک متد abstract را خارج از کلاس abstract تعرف کنید.
  • وقتی که یک کلاس sealed می شود، نمی تواند ارث بری شود.بنابراین کلاس های abstract نمی توانند به صورت sealed تعریف شوند.
  • برنامه زیر نمونه ای گروه نظری را توضیح می دهد.

در زیر کلاس abstract توضیح داده شده است

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("Rectangle class area :");
         return (width * length); 
      }
   }

   class RectangleTester
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(10, 7);
         double a = r.area();
         Console.WriteLine("Area: {0}",a);
         Console.ReadKey();
      }
   }
}

نتیجه ی اجرای قطعه کد بالا به صورت زیر است:

Rectangle class area :
Area: 70

وقتی شما تابعی را در یک کلاس تعریف کرده اید و می خواهید آن تابع را در کلاس فرزند آن ، پیاده سازی کنید، باید از توابع virtual (مجازی) استفاده کنید. توابع مجازی می توانند،در کلاس های فرزند مختلف، به به طور متفاوت پیاده سازی شوند و فراخوانی هر کدام این توابع در زمان اجرا، تصمیم گیری خواهد شد.

Polymorphism پویا توسط کلاس های انتزاعی (abstract classes) و توابع مجازی (virtual functions) انجام می شود.

ای مطلب در مثال زیر توضیح داده می شود

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("Parent class area :");
         return 0;
      }
   }
   class Rectangle: Shape
   {
      public Rectangle( int a=0, int b=0): base(a, b)
      {

      }
      public override int area ()
      {
         Console.WriteLine("Rectangle class area :");
         return (width * height); 
      }
   }
   class Triangle: Shape
   {
      public Triangle(int a = 0, int b = 0): base(a, b)
      {
      
      }
      public override int area()
      {
         Console.WriteLine("Triangle class area :");
         return (width * height / 2); 
      }
   }
   class Caller
   {
      public void CallArea(Shape sh)
      {
         int a;
         a = sh.area();
         Console.WriteLine("Area: {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 class area:
Area: 70
Triangle class area:
Area: 25