سه شنبه ۱۸ دي ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش سی شارپ - چندریختی

کلمه‌ی چندریختی (polymorphism) به معنای داشتن چندین شکل است. در الگوی برنامه‌نویسی شیءگرا، چندریختی اغلب به عنوان 'یک رابط، چندین تابع' بیان می‌شود.

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

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

مکانیزم پیوند یک تابع با یک شیء در زمان کامپایل، پیوند زودهنگام نامیده می‌شود. همچنین به آن پیوند استاتیک هم گفته می‌شود. C# دو تکنیک برای پیاده‌سازی چندریختی استاتیک فراهم می‌کند. آن‌ها عبارتند از:

  • سربارگذاری تابع (Function Overloading)
  • سربارگذاری عملگر (Operator Overloading)

در درس بعد به بحث درباره سربارگذاری عملگر می‌پردازیم.

سربارگذاری تابع (Function Overloading)

شما می‌توانید تعدادی تعریف برای یک نام تابع در یک دامنه داشته باشید. تعریف تابع باید از یکدیگر با تفاوت در نوع و/یا تعداد آرگومان‌ها در لیست آرگومان‌ها متفاوت باشند. شما نمی‌توانید تعریف‌های تابعی را که تنها در نوع برگشت تفاوت دارند، سربارگذاری کنید.

مثال زیر نشان‌دهنده استفاده از تابع چاپ (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++

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

در زبان برنامه‌نویسی C# شما می‌توانید کلاس‌های انتزاعی (abstract) ایجاد کنید که برای ارائه بخشی از پیاده‌سازی یک رابط استفاده می‌شوند. پیاده‌سازی وقتی تکمیل می‌شود یک کلاس مشتق شده از آن ارث بری می‌کند. کلاس‌های انتزاعی شامل متدهای انتزاعی هستند که توسط کلاس مشتق شده پیاده‌سازی می‌شوند. کلاس‌های مشتق شده دارای قابلیت‌های تخصصی بیشتری هستند.

در ادامه قوانینی درباره کلاس‌های انتزاعی آمده است −

  • شما نمی‌توانید یک نمونه از یک کلاس انتزاعی ایجاد کنید

  • شما نمی‌توانید یک متد انتزاعی را خارج از یک کلاس انتزاعی تعریف کنید

  • زمانی که یک کلاس با کلیدواژه 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("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) استفاده می‌کنید. توابع مجازی می‌توانند در کلاس‌های مشتق مختلف به صورت متفاوت پیاده‌سازی شوند و فراخوانی این توابع در زمان اجرا تعیین می‌شود.

چندریختی پویا توسط کلاس‌های انتزاعی (abstract classes) و توابع مجازی پیاده‌سازی می‌شود.

برنامه زیر این را نشان می‌دهد −

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