پلی مورفیسم در برنامه نویسی چیست؟ — مفهوم به زبان ساده + مثال

۵۵۸۹ بازدید
آخرین به‌روزرسانی: ۱۵ اسفند ۱۴۰۲
زمان مطالعه: ۲۲ دقیقه
پلی مورفیسم در برنامه نویسی چیست؟ — مفهوم به زبان ساده + مثال

برنامه نویسی شی گرا دارای مفاهیم و اصول مختلفی است که این اصول به توسعه دهندگان اجازه می‌دهند تا کدهای منطقی تولید کنند. یکی از مفاهیم و اصول مهم شی گرایی ،‌ چندریختی در برنامه نویسی یا پلی مورفیسم در برنامه نویسی (Polymorphism) است. اما سوالی که مطرح می‌شود این است که پلی مورفیسم در برنامه نویسی چیست و چند ریختی به چه معناست. در این مقاله سعی شده است تا به‌طور جامع و به بیان ساده به این سوال پاسخ داده شود. همچنین مفهوم پُلی مورفیسم در تعدادی از زبان‌های برنامه نویسی مطرح نیز شرح و آموزش داده شده است. در این مقاله برای درک بهتر مفهوم چندریختی یا پلی مورفیسم در برنامه نویسی ، مثال‌های متعددی به زبان‌های برنامه نویسی مختلف ارائه شده است.

فهرست مطالب این نوشته

پلی مورفیسم چیست ؟

اگر به‌طور کلی این سوال وجود داشته باشد که پلی مورفیسم چیست باید گفت که پلی مورفیسم (Polymorphism | چندریختی) که واژه‌ای یونانی به حساب می‌آید، در لغت به معنی «داشتن چندین شکل و فُرم مختلف» است. در کل اصطلاح Polymorphism یعنی:

  • شرایط رخ دادن و به وقوع پیوستن در فُرم‌های مختلف

در سطح پایه آن، پلی مورفیسم بخشی از نظریه نوع (Type Theory) در ریاضیات به حساب می‌آید. در علوم کامپیوتر و برنامه نویسی شی گرا ، شی دارای چند ریختی به شیئی گفته می‌شود که می‌تواند چندین فُرم و شکل را به خود بگیرد. اصطلاح پلی مورفیسم در زیست‌شناسی و علم ژنتیک نیز کاربرد دارد.

پلی مورفیسم چیست ؟

پلی مورفیسم در زیست‌شناسی به چه معناست؟

پلی مورفیسم در زیست‌شناسی به معنی رخداد فُرم‌ها و شکل‌های مختلف در میان اعضای یک جمعیت یا اجتماع (Colony)، یا به وقوع پیوستن اشکال گوناگون در چرخه حیات یک جاندار است.

پلی مورفیسم در ژنتیک به چه معناست؟

پلی مورفیسم در ژنتیک به وجود گونه‌های مختلف ژنتیکی در یک جمعیت اشاره دارد که انتخاب طبیعی بر اساس آن عمل می‌کند.

اما موضوع اصلی بحث این مقاله، پلی مورفیسم در برنامه نویسی است. بنابراین، در ادامه یاد می‌گیریم که پلی مورفیسم در برنامه نویسی چیست و مثال‌هایی هم برای درک بهتر این مفهوم ارائه شده است.

مثال هایی از چندریختی در دنیای واقعی

به عنوان مثال در دنیای واقعی، یک شخص می‌تواند روابط متفاوتی را با افراد مختلف داشته باشد. یک بانو می‌تواند به‌طور همزمان هم مادر، هم خواهر و هم دوست باشد. این یعنی فرد می‌تواند رفتارهای متفاوتی را در شرایط مختلف از خود نشان دهد.

پلی مورفیسم مثال

به عنوان یک مثال دیگر هم می‌توان به بدن انسان اشاره کرد. بدن انسان ارگان‌های متفاوتی دارد. هر ارگان کارکرد و قابلیت عملکردی متفاوتی را از خود نشان می‌دهد. قلب انسان مسئولیت پمپاژ جریان خون را بر عهده دارد، ریه‌ها برای نفس کشیدن هستند، مغز انسان برای فعالیت‌های شناختی مورد استفاده قرار می‌گیرد و کلیه‌ها برای دفع مواد زائد به کار گرفته می‌شوند. بنابراین، یک تابع متُد استاندارد وجود دارد که بسته به ارگان بدن، کار متفاوتی را انجام می‌دهد.

پلی مورفیسم در برنامه نویسی به بیان ساده

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

حالا اگر ورودی‌هایی با «نوع داده» متفاوت به این تابع وارد شوند، آیا این تابع باز هم خروجی تولید خواهد کرد؟ خیر. دلیلش این است که کدهای تابع انتظار دریافت نوع داده دیگری را ندارند و تنها می‌توانند عملیات مربوطه را روی نوع خاصی از داده‌ها مثلاً اعداد صحیح (Integer) انجام دهند. بنابراین، در این حالت، اجرای کدها با خطا مواجه خواهد شد. چندریختی یا پلی مورفیسم در برنامه نویسی برای حل این مشکل به وجود آمده است. حالا به بیان ساده پلی مورفیسم در برنامه نویسی چیست ؟

پلی مورفیسم در واقع به این صورت است که چندین نسخه مختلف از همان کدها نوشته می‌شوند و هر نسخه از این کدها یا توابع، ورودی‌هایی با نوع داده متفاوت را می‌پذیرند. مثلاً مطابق تصویر زیر، نسخه اول تنها نوع (شی) سگ از کلاس حیوان را به عنوان ورودی می‌پذیرد، نسخه دوم، نوع گربه و نسخه سوم هم تنها نوع گاو را در ورودی قبول می‌کند. نکته مهم این است که نام‌های تمام این نسخه‌های کد یکسان هستند. برای مثال، نام همه بلوک‌کدها در تصویر زیر «C» است. همچنین، این نسخه‌های متفاوت با نام یکسان، عملیات یکسانی را هم انجام می‌دهند و تنها نوع داده ورودی متفاوتی را می‌پذیرند. به این ترتیب، دیگر خطایی به وجود نخواهد آمد و تمام نسخه‌ها خروجی لازم را تولید خواهند کرد.

بنابراین، به بیان ساده، پلی مورفیسم در برنامه نویسی و شی گرایی ، تولید یک بلوک کُد یکسان و مهم‌تر از همه، تعیین یک نام واحد و یکسان برای آن با این قابلیت است که آرگومان‌ها، متغیرها یا همان ورودی‌هایی با نوع داده متفاوت را می‌توان به آن وارد کرد. به واسطه قابلیت چندریختی، برنامه این امکان را خواهد داشت تا با مشخص شدن نوع داده ورودی، کد مناسب و مختص به آن نوع داده خاص را روی ورودی‌ها اجرا کند. مثلاً اگر نوع داده یا شی ورودی سگ باشد، کدهای مخصوص نوع سگ اجرا خواهند شد.

یعنی مثلاً اگر متُدی به نام speak()‎   وجود داشته باشد و ورودی از نوع گربه یا Cat باشد، متد speak()‎   مربوط به گربه اجرا خواهد شد و اگر ورودی از نوع گاو باشد، متد speak()‎ مخصوص گاو اجرا می‌شود. بنابراین پلی مورفیسم در برنامه نویسی به بیان ساده، استفاده از یک بلوک کد و تغییر «نسخه» آن بلوک کد، بر اساس نوع ورودی‌ها است.

پلی مورفیسم در برنامه نویسی چیست ؟

پلی مورفیسم یکی از مفاهیم کلیدی برنامه نویسی شی گرا (Object Oriented Programming | OOP) و در واقع سومین رُکن و ستون OOP به حساب می‌آید. به‌طور کلی، چندریختی یا همان Polymorphism مربوط به شرایطی می‌شود که در آن یک چیز در شکل‌های مختلف ظاهر می‌شود یا یک رویداد در فُرم‌های گوناگون اتفاق می‌افتد. اصطلاح چندریختی یا پلی مورفیسم در برنامه نویسی و علوم کامپیوتر به این معنا است که می‌توان به اشیایی با انواع مختلف از طریق رابط و واسطی یکسان دسترسی داشت. هر نوع می‌تواند پیاده‌سازی مستقل خود را از این واسط فراهم کند.

به بیان دقیق‌تر، در حوزه‌های زبان‌های برنامه نویسی و «نظریه نوع» (Type Theory)، پلی مورفیسم فراهم‌سازی واسطی یکه و واحد برای موجودیت‌هایی با نوع داده‌های گوناگون یا استفاده از یک نماد واحد برای بازنمایی چندین نوع مختلف است. پلی مورفیسم در برنامه نویسی شی گرا ضرورت پیدا می‌کند. اشیاء بر اساس کلاس‌های مختلف تعریف و ایجاد می‌شوند. اشیاء می‌توانند خصوصیت‌ها (Property) و متُدهایی (Method) داشته باشند.

 پلی مورفیسم به چه معناست

چگونه می توان تعیین کرد یک شی پلی مورفیک است؟

برای اینکه بتوان مشخص کرد که آیا یک شی دارای حالت چندریختی یا به اصطلاح «پلی مورفیک» (Polymorphic) هست یا خیر، می‌توان یک آزمایش ساده انجام داد. در صورتی که آزمون‌های «is-a» (آیا هست؟) یا «instanceof» (نمونه‌ای از) برای آن شی موفقیت‌آمیز باشند، آن شی چندریختی دارد و به اصطلاح «پلی مورفیک» است. instanceof یک عملگر دودویی به حساب می‌آید که برای بررسی نوع داده یک شی به‌کار می‌رود. در واقع با استفاده از عملگر instanceof می‌توان مشخص کرد که آیا یک شی دارای نوع داده مربوطه هست یا خیر؟

پلی مورفیسم زمانی اتفاق می‌افتد که «وراثت» (ارث‌بری | Inheritance) وجود داشته باشد؛ یعنی کلاس‌های بسیاری مرتبط با هم و مشتق شده از یکدیگر ایجاد شده باشند. همان‌طور که در خصوص وراثت، یکی دیگر از اصول و مفاهیم شی گرایی، مطرح می‌شود، برای مثال تمام کلاس‌های جاوا، کلاس Object را بسط می‌دهند و به همین دلیل، تمام اشیاء در جاوا پلی مورفیک هستند. زیرا حداقل دو آزمون instanceof در مورد آن‌ها موفقیت‌آمیز است.

مثال خودرو برای درک بهتر مفهوم پلی مورفیسم در برنامه نویسی

برای مثال، می‌توان شیئی را از کلاس خودرو (Car) ایجاد و تعریف کرد. خصوصیت‌ها و متُدهایی که این خودرو می‌توانند داشته باشند به شرح زیر است:

  • Properties (خصوصیت‌ها): رنگ، شرکت سازنده، مدل، سرعت فعلی
  • Methods (متدها): متُدها همان توابع یا عملکردهایی هستند که به وسیله کلاس فراخوانی می‌شوند. برای مثال می‌توان مواردی نظیر حرکت کردن، توقف، پارک کردن، پیچیدن به چپ یا راست را نام برد.
مثال کلاس و شی در شی گرایی

حالا برای اینکه شیً ماشین فوق، پلی مورفیک و دارای قابلیت چندریختی باشد، خصوصیت‌ها و متُدهای آن را می‌توان با استفاده از نام کلاس یکه و واحد یعنی «Car» فراخوانی کرد، اما بسته به اینکه این کلاس چگونه در کدها استفاده می‌شود، نوع داده‌های متفاوتی فراخوانی خواهند شد.

فیلم های آموزش برنامه نویسی

فیلم های آموزش برنامه نویسی فرادرس

چندریختی یا پلی مورفیسم در برنامه نویسی زیرمجموعه‌ای از مفاهیم شی گرایی به حساب می‌آید و شی‌گرایی هم یکی از مهم‌ترین مباحث و موضوع‌ها در یادگیری مهارت برنامه نویسی محسوب می‌شود. حیطه برنامه نویسی روز‌به‌روز محبوبیت بیش‌تری پیدا می‌کند و این حوزه یکی از پرتقاضا‌ترین زمینه‌های شغلی در دنیای کسب و کار به شمار می‌رود. درآمد بالای برنامه نویسی و موقعیت‌های شغلی زیادی که در این حوزه وجود دارد باعث شده است که افراد زیادی به دنبال یادگیری برنامه نویسی باشند. یکی از بهترین و مقرون به صرفه‌ترین روش‌های یادگیری برنامه نویسی استفاده از دوره‌های آموزش آنلاین محسوب می‌شود.

فرادرس یکی از بزرگ‌ترین مجموعه‌های آموزش برنامه نویسی را در وب سایت خود ارائه کرده است. دوره‌های آموزش برنامه نویسی فرادرس بسیار متنوع هستند و برای اکثر زبان‌های برنامه نویسی، شیوه‌ها، رویکردها و ابزارهای مختلف برنامه نویسی، دوره‌های آموزشی متعددی ارائه شده است. حتی دوره‌ها و فیلم‌های آموزشی رایگان و غیر رایگانی هم برای آموزش مفاهیم شی‌گرایی در وب سایت فرادرس و صفحه مجموعه دوره‌های برنامه نویسی وجود دارند که علاقه‌مندان می‌توانند علاوه بر مطالعه این مقاله، برای یادگیری بیش‌تر از این دوره‌ها هم استفاده کنند.

انواع Polymorphism چیست ؟

می‌توان گفت که ۴ نوع اصلی پلی مورفیسم در برنامه نویسی وجود دارد. این ۴ نوع Polymorphism در ادامه فهرست شده‌اند:

  • پلی مورفیسم زیرنوع یا Subtype Polymorphism (زمان اجرا | Runtime)
  • چندریختی پارامتری یا Parametric Polymorphism (زمان کامپایل | Compile-time)
  • پلی مورفیسم موردی یا Ad hoc Polymorphism (سربارگذاری | Overloading)
  • چندریختی تبدیل نوع خودکار یا Coercion Polymorphism (تبدیل نوع موقت | Casting)

اکنون در ادامه به شرح هر یک از انواع پلی مورفیسم پرداخته شده است.

Subtype Polymorphism چیست ؟

«پلی مورفیسم زیرنوع» (Subtype Polymorphism) که به آن «Inclusion Polymorphism» (پلی مورفیسم شمولی یا دربرداری) هم می‌گویند، رایج‌ترین نوع چندریختی به حساب می‌آید. معمولاً زمانی که گفته می‌شود شیئی چندریختی دارد، در واقع منظور همین پلی مورفیسم زیرنوع است.

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

در پلی مورفیسم زیرنوع، از یک نام کلاس برای ارجاع همزمان به چندین زیرنوع استفاده می‌شود. در مثال خودرو که پیش‌تر به آن اشاره شد، شی کلاس «Car» ایجاد شده و می‌توان چندین زیرنوع از آن تعریف کرد. این زیرنوع‌ها مثلاً می‌توانند موارد زیر باشند:

  • فورد
  • شورلت
  • کیا
  • نیسان
  • فولکس‌واگن
  • BMW
  • آئودی
  • تسلا

همچنین، هر خودرو دارای خصوصیت رنگ مربوط به خودش است و علاوه بر آن، خصوصیت‌های دیگری هم وجود دارند. می‌توان به تمام زیرنوع‌ها تنها با استفاده از کلاس Car ارجاع داد. هر خودرو در کلاس Car دارای خصوصیت (Property) رنگ یا همان «color» است و حالا می‌توان رنگ مربوطه را از هر زیرنوع کلاس ماشین دریافت کرد.

می‌توان تابعی نوشت تا کار دریافت رنگ هر یک از زیرنوع‌های کلاس Car را انجام دهد. این تابع می‌تواند چیزی شبیه به کدهای زیر باشد. کدهای زیر تقریباً به صورت شبه‌کد هستند و به زبان برنامه نویسی خاصی نوشته نشده‌اند:

1getColor(BMW)
2→ returns red
3getColor(Audi)
4→ returns blue
5getColor(Kia)
6→ returns yellow

در کدهای فوق در صورت فراخوانی getColor   برای هر یک از زیرنوع‌های کلاس Car مثل BMW، رنگ مربوط به آن بازگردانده می‌شود.

مثال پلی مورفیسم در C++‎ از نوع Inclusion

در C++‎ برای رسیدن به چندریختی زیرنوع یا شمولی، نیاز به «تابع مجازی» (Virtual Function) وجود دارد. در مثال زیر، دو «کلاس پایه» (‌Base Class) و «کلاس مشتق شده» (Derived Class) تعریف شده‌اند که هر کدام یک متد در فضای عمومی خود دارند.

1#include<iostream>
2using namespace std;
3class Base {
4   public:
5      virtual void print() {
6         cout << "This is base class." << endl;
7      }
8};
9class Derived : public Base {
10   public:
11      void print() {
12         cout << "This is derived class." << endl;
13      }
14};
15int main() {
16   Base *ob1;
17   Base base_obj;
18   Derived derived_obj;
19   ob1 = &base_obj; //object of base class
20   ob1->print();
21   ob1 = &derived_obj; //same pointer to point derived object
22   ob1->print();
23}

هر یک از این متدها، متن خاص و متفاوتی را در خروجی چاپ می‌کنند. باید توجه شود که متُد مربوط به کلاس پایه تابعی مجازی است. در تابع main این برنامه، یک اشاره‌گر از نوع کلاس پایه و دو شی برای هر کدام از کلاس‌های base و derived تعریف شده است.

ملاحظه می‌شود که به واسطه وجود چندریختی از نوع Inclusion در C++‎، می‌توان از همان اشاره‌گری برای اشاره به شی مشتق شده استفاده کرد که برای اشاره به شی مربوط به کلاس پایه به کار گرفته شده است. خروجی کدهای فوق در ادامه آمده است:

This is base class.
This is derived class.

Parametric Polymorphism چیست ؟

«چندریختی پارامتری» (Parametric Polymorphism) به‌طور خاص روشی را برای استفاده از یک تابع (کدهای یکسان) برای تعامل با چندین نوع داده مختلف فراهم می‌کند. چندریختی پارامتری را «Early Binding» هم می‌نامند که می‌توان آن را «پیوند زودهنگام» ترجمه کرد. این نوع از پلی مورفیسم امکان استفاده از کدهای یکسانی را برای نوع داده‌های مختلف فراهم می‌کند.

مثال چندریختی در برنامه نویسی پایتون از نوع پارامتری

یک مثال در این خصوص می‌تواند فهرستی از انواع مختلف باشد. در چندریختی پارامتری می‌توان عنصرهای این لیست را صرف نظر از نوع آن عنصر حذف، اضافه یا جایگزین کرد.

در ادامه کدهایی آمده‌اند که یک تابع دارای چندریختی پارامتری را در پایتون نمایش می‌دهند:

1for (element in list):
2list.remove(element)

مثال چندریختی در C++‎ از نوع پارامتری

در C++‎ می‌توان چندریختی پارامتری را با استفاده از قالب‌ها (Templateها) درک کرد:

1#include<iostream>
2using namespace std;
3template <class T>
4T maximum(T a, T b) {
5   if(a > b) {
6      return a;
7   } else {
8      return b;
9   }
10}
11int main() {
12   cout << "Max of (156, 78): " << maximum(156, 78) << endl;
13   cout << "Max of (A, X): " << maximum('A', 'X') << endl;
14}

خروجی کدهای فوق به صورت زیر است:

Max of (156, 78): 156
Max of (A, X): X

Ad hoc Polymorphism چیست ؟

در «پلی مورفیسم موردی» (Ad hoc Polymorphism)، توابع با نام یکسان برای انواع مختلف رفتار متفاوتی از خود نشان می‌دهند و به صورت موردی عمل می‌کنند. در واقع در این نوع از چندریختی، یک تابع واحد، برای نوع داده‌های مختلف رفتار متفاوتی دارد. در صورتی که قابلیت پلی مورفیسم Ad hoc وجود داشته باشد، هم تابع و هم عملگر هر دو می‌توانند «سرریز» (Overload) شوند. برخی از زبان‌های برنامه نویسی اجازه «بار اضافی دادن به تابع» (Function Overloading) را نمی‌دهند.

مثال پلی مورفیسم در C++‎ از نوع Ad hoc

در این بخش مثالی به زبان C++‎ برای نشان دادن چندریختی Ad hoc ارائه شده است. در این مثال تابعی به نام add دو بار با نام یکسان تعریف شده است که در حالت اول اعداد از نوع صحیحی را می‌پذیرد و با هم جمع می‌کند و در حالت دوم، مقادیر رشته‌ای را دریافت و با هم ادغام می‌کند:

1#include<iostream>
2using namespace std;
3int add(int a, int b) {
4   return a + b;
5}
6string add(string a, string b) {
7   return a + b; //concatenate
8}
9int main() {
10   cout << "Addition of numbers: " << add(2, 7) << endl;
11   cout << "Addition of Strings: " << add("hello", "World") << endl;

خروجی کدهای فوق به صورت زیر است:

Addition of numbers: 9
Addition of Strings: helloWorld

مثال پلی مورفیسم در پایتون از نوع Ad hoc

نوع‌گذاری یا تعیین نوع در پایتون به صورت پویا است و پایتون به اصطلاح زبانی «Dynamically Typed» به حساب می‌آید. یعنی در پایتون الزامی برای تعیین نوع و مشخص کردن نوع داده برای موجودیت‌های مختلفی مثل متغیرها وجود ندارد.

تابع جمع در پایتون به صورت خود به خود دارای قابلیت چندریختی موردی است؛ زیرا عملیات جمع یا «+» تابعی واحد و یکتا است که می‌توان آن را روی نوع داده‌های مختلف اجرا کرد. مثلاً با تابع جمع که برای فراخوانی آن از علامت به اضافه (+) استفاده می‌شود، هم می‌توان اعداد از نوع اعشاری (Float) را با هم جمع کرد و هم امکان جمع کردن اعداد با نوع صحیح (Integer) یا حتی رشته‌ها (String) نیز وجود دارد.

مثلاً در قطعه کد زیر، ابتدا دو عدد از نوع صحیح با هم جمع شده‌اند و سپس با استفاده از همان علامت به اضافه (یعنی تابع جمع) دو داده از نوع رشته‌ای با هم جمع یا به اصطلاح تلفیق (Concatenate) شده‌اند:

13 + 4
2"Foo" + "bar"

عملیات جمع در هر یک از خط کدهای فوق مقداری را از همان نوع داده‌های مورد استفاده در هر گزاره جمع باز می‌گرداند. یعنی حاصل جمع دو عدد صحیح، عددی از نوع صحیح و حاصل تلفیق یا جمع دو داده رشته‌ای هم یک داده رشته‌ای خواهد بود. خروجی کدهای فوق در ادامه آمده است:

→ 7
→ "Foobar"

همان‌طور که در خروجی کدها ملاحظه می‌شود، حاصل جمع 3 + 4   عددی از نوع Integer یعنی 7   است و در جمع دو رشته “Foo” + “bar”   نیز تلفیق آن‌ها انجام شده و خروجی از نوع رشته‌ای و به صورت “Foobar”   است.

Coercion Polymorphism چیست ؟

«چندریختی تبدیل نوع خودکار» (Coercion Polymorphism) که «Casting» هم نامیده می‌شود، تبدیل مستقیم یک نوع داده به نوع دیگر است. این نوع از پلی مورفیسم در برنامه نویسی زمانی اتفاق می‌افتد که یک نوع داده به نوع دیگر تبدیل یا به اصطلاح Cast می‌شود. پیش از این، چندریختی از طریق تعامل با نوع داده‌های مختلف به واسطه شی کلاس یا توابع انجام می‌شد. نوع یک شی زمانی قابل انتخاب بود که برنامه اجرا می‌شد. امکان اجرای یک تابع واحد روی انواع داده مختلف نیز وجود داشت.

برای ارائه مثالی ساده در این خصوص، مي‌توان تبدیل مقادیر عددی از نوع صحیح (int) به نوع اعشاری (double)، اعشاری شناور (float) و برعکس را نام برد. بسته به زبان برنامه نویسی، یا نوع را می‌توان در زمان تعریف متغیر مشخص کرد و گاهی هم متُدی برای نوع داده وجود دارد که مقدار متغیرها را به نوع دیگر تبدیل می‌کند. در ادامه مثالی برای درک بهتر پلی مورفیسم در برنامه نویسی به زبان‌های مختلف از نوع Coercion ارائه شده است. به‌طور کلی دو نوع Casting وجود دارد:

  • «تبدیل نوع موقت ضمنی» (غیر‌صریح | غیر‌واضح) یا «Implicit Casting»: با استفاده از خود کامپایلر انجام می‌شود.
  • «تبدیل نوع موقت صریح» (آشکار | واضح) یا «Explicit Casting»: با استفاده از const_cast  ، dynamic_cast   و سایر موارد انجام می‌شود.

مثالی برای پلی مورفیسم Coercion در برنامه نویسی به زبان های مختلف

برای مثال در پایتون، تبدیل نوع داده‌ها مشابه کدهای زیر انجام می‌شود:

1int(43.2) #Converts a double to an int
2float(45) #Converts an int to a float

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

در زبان جاوا نوع داده متغیرها به سادگی و تنها با تعریف نوع هر متغیر تبدیل می‌شود. در ادامه مثال ساده‌ای برای جاوا در این خصوص ارائه شده است:

1int num = 23;
2double dnum = num;

همچنین، تبدیل نوع در جاوا به صورت زیر هم انجام می‌شود:

1double dnum = Double.valueOf(inum);

در ادامه هم مثالی برای Coercion Polymorphism در زبان C++‎ ارائه شده است:

1#include<iostream>
2using namespace std;
3class Integer {
4   int val;
5   public:
6      Integer(int x) : val(x) {
7   }
8   operator int() const {
9      return val;
10   }
11};
12void display(int x) {
13   cout << "Value is: " << x << endl;
14}
15int main() {
16   Integer x = 50;
17   display(100);
18   display(x);
19}

خروجی کدهای فوق به صورت زیر است:

Value is: 100
Value is: 50

پلی مورفیسم در جاوا

درست مثل مفهوم کلی پلی مورفیسم در برنامه نویسی ، در جاوا هم پلی مورفیسم به توانایی یک کلاس برای فراهم کردن پیاده‌سازی‌های مختلفی از یک متُد، بسته به نوع شیئی اشاره دارد که به آن متُد ارجاع داده می‌شود.

به بیان ساده، پلی مورفیسم در جاوا به برنامه نویس امکان می‌دهد تا عملکرد یکسانی را به شکل‌های مختلف اجرا کند. هر شی جاوایی که نتیجه بیش از یک آزمون IS-A برای نوع داده خودش و همچنین برای شی کلاس مربوطه مثبت باشد، پلی مورفیک به حساب می‌آید.

در جاوا هم پلی مورفیسم زمانی اتفاق می‌افتد که وراثت برقرار باشد. وراثت قابلیتی قدرتمند در جاوا به حساب می‌آید. وراثت جاوا این امکان را برای یک کلاس فراهم می‌کند تا از خصوصیت‌ها و ویژگی‌های کلاس‌های دیگر استفاده کنند و آن‌ها را به ارث ببرند. به این ترتیب، این امکان در جاوا فراهم می‌شود تا بتوان عملکرد و رفتار یکسانی را به شکل‌های مختلف انجام داد.

مثال پلی مورفیسم در برنامه نویسی جاوا

در این مثال، یک ابَر کلاس به نام Shapes   دارای متُدی به نام area()   است. زیرکلاس‌های کلاس Shapes می‌توانند از نوع مثلث ( Triangle  )، دایره ( circle  )، مستطیل ( Rectangle  ) و سایر موارد باشند. استفاده از ارث‌بری و پلی مورفیسم در جاوا به این معنا است که زیرکلاس‌ها می‌توانند از متُد area()   برای پیدا کردن فرمول مساحت مربوط به آن شی استفاده کنند.

1class Shapes {
2  public void area() {
3    System.out.println("The formula for area of ");
4  }
5}
6class Triangle extends Shapes {
7  public void area() {
8    System.out.println("Triangle is ½ * base * height ");
9  }
10}
11class Circle extends Shapes {
12  public void area() {
13    System.out.println("Circle is 3.14 * radius * radius ");
14  }
15}
16class Main {
17  public static void main(String[] args) {
18    Shapes myShape = new Shapes();  // Create a Shapes object
19    Shapes myTriangle = new Triangle();  // Create a Triangle object
20    Shapes myCircle = new Circle();  // Create a Circle object
21    myShape.area();
22    myTriangle.area();
23    myShape.area();
24    myCircle.area();
25  }
26}

خروجی کدهای فوق به صورت زیر است:

The formula for the area of Triangle is ½ * base * height
The formula for the area of the Circle is 3.14 * radius * radius

پیش از این مقاله‌ای با عنوان «پلی مورفیسم در جاوا» نیز در مجله فرادرس منتشر شده است که برای یادگیری کامل‌تر مباحث مربوط به پلی مورفیسم در جاوا مطالعه آن به علاقه‌مندان پیشنهاد می‌شود:

آموزش پلی مورفیسم در سی شارپ

پلی مورفیسم در برنامه نویسی سی‌شارپ هم بسیار کاربرد دارد. در این بخش به چندریختی در C#‎ پرداخته شده است. ابتدا لازم است ویژگی های پلی مورفیسم در سی شارپ بررسی شوند.

ویژگی های پلی مورفیسم در سی شارپ چیست ؟

پلی مورفیسم در برنامه نویسی سی شارپ دارای دو جنبه متمایز است که هر یک در ادامه فهرست شده‌اند:

  • در زمان اجرا، با اشیای یک کلاس مشتق شده، به عنوان اشیای یک کلاس پایه رفتار می‌شود. این رفتار در خصوص مواردی مثل پارامترهای متُد و مجموعه‌هایی از آرایه‌ها صورت می‌گیرد. وقتی این نوع از چندریختی در برنامه نویسی اتفاق می‌افتد، نوع داده اعلان شده برای آن شی دیگر با نوع داده زمان اجرای آن، همسان نخواهد بود.
  • کلاس‌های پایه، متُدهای مجازی را تعریف و پیاده‌سازی می‌کنند و کلاس‌های مشتق شده می‌توانند آن‌ها را بازنویسی (Override) کنند. این یعنی آن‌ها تعریف و پیاده‌سازی مختص خودشان را فراهم می‌سازند. در زمان اجرا، وقتی که کدهای کلاینت متُد مربوطه را فراخوانی می‌کنند، «زمان اجراي زبان مشترک» (Common Language Runtime) که به اختصار آن را CLR می‌نامند، نوع داده زمان اجرای شی را بررسی و سپس نسخه بازنویسی شده ماشین مجازی را فراخوانی می‌کند. برنامه نویس در کدهای منبع خود می‌تواند متُدی را روی یک کلاس پایه فراخوانی کند و باعث شود که یک نسخه مشتق شده از آن متُد اجرا شود.

متُدهای مجازی در سی شارپ این امکان را فراهم می‌کنند تا بتوان با گروه‌هایی از اشیای مرتبط به شکلی یکپارچه کار کرد. برای درک بهتر چندریختی در سی‌شارپ، بهتر است مثالی انتزاعی ارائه شود.

مثالی برای درک بهتر پلی مورفیسم در برنامه نویسی سی شارپ

برای مثال، فرض می‌شود که یک اپلیکیشن رسم شکل‌های مختلف وجود داشته باشد که به کاربر امکان می‌دهد تا شکل‌های مختلف (دایره، مثلث و مستطیل) را روی سطح رسم ایجاد کند. حالا فرض می‌شود که این اپلیکیشن باید بر انواع شکل‌های مختلفی که ایجاد شده‌اند نظارت داشته باشد و به‌روزرسانی‌های لازم را در پاسخ به حرکت‌های ماوس کاربر نشان دهد. برای حل کردن این مسئله، می‌توان در دوگام ساده از پلی مورفیسم استفاده کرد:

  1. ایجاد یک سلسله مراتب کلاس که در آن هر شکل مشخص از یک کلاس پایه مشترک مشتق می‌شود.
  2. استفاده از یک متُد مجازی برای فراخوانی متُد مناسب در هر کلاس مشتق شده از طریق یک فراخوانی به متد کلاس پایه

ابتدا باید یک کلاس پایه را به نام Shape ایجاد کرد و پس از آن، کلاس‌های مشتق شده نظیر Rectangle  ، Circle   و Triangle   هم باید ایجاد شوند. حالا باید برای کلاس Shape   متدی مجازی به نام Draw   ایجاد شود و آن را در هر کدام از کلاس‌های مشتق شده بازنویسی کرد. سپس در این مثال، یک شی List<Shape>   ایجاد شده و یک Circle  ، Triangle   و Rectangle   به آن اضافه شده است.

1public class Shape
2{
3    // A few example members
4    public int X { get; private set; }
5    public int Y { get; private set; }
6    public int Height { get; set; }
7    public int Width { get; set; }
8
9    // Virtual method
10    public virtual void Draw()
11    {
12        Console.WriteLine("Performing base class drawing tasks");
13    }
14}
15
16public class Circle : Shape
17{
18    public override void Draw()
19    {
20        // Code to draw a circle...
21        Console.WriteLine("Drawing a circle");
22        base.Draw();
23    }
24}
25public class Rectangle : Shape
26{
27    public override void Draw()
28    {
29        // Code to draw a rectangle...
30        Console.WriteLine("Drawing a rectangle");
31        base.Draw();
32    }
33}
34public class Triangle : Shape
35{
36    public override void Draw()
37    {
38        // Code to draw a triangle...
39        Console.WriteLine("Drawing a triangle");
40        base.Draw();
41    }
42}

در این مثال، برای به‌روزرسانی سطح رسم، از یک حلقه foreach استفاده شده است تا در طول لیست مربوطه پیمایش کند و متد Draw را روی هر شی Shape در این لیست فراخوانی کند. اگرچه، هر شی در لیست دارای نوع تعریف شده‌ای از Shape است، این نوع زمان اجرا (نسخه بازنویسی شده متُد در هر کلاس مشتق شده) است که فراخوانی خواهد شد.

1// Polymorphism at work #1: a Rectangle, Triangle and Circle
2// can all be used whereever a Shape is expected. No cast is
3// required because an implicit conversion exists from a derived
4// class to its base class.
5var shapes = new List<Shape>
6{
7    new Rectangle(),
8    new Triangle(),
9    new Circle()
10};
11
12// Polymorphism at work #2: the virtual method Draw is
13// invoked on each of the derived classes, not the base class.
14foreach (var shape in shapes)
15{
16    shape.Draw();
17}
18/* Output:
19    Drawing a rectangle
20    Performing base class drawing tasks
21    Drawing a triangle
22    Performing base class drawing tasks
23    Drawing a circle
24    Performing base class drawing tasks
25*/

در سی‌شارپ، همه نوع‌ها پلی مورفیک هستند، زیرا تمام نوع‌ها که شامل نوع‌های تعریف شده توسط کاربر هم می‌شوند از Object   ارث‌بری می‌کنند. پایتون هم یکی دیگر از زبان‌های محبوبی به حساب می‌آید و افراد زیادی به دنبال یادگیری پلی مورفیسم در پایتون هستند. بنابراین بهتر است در ادامه به این موضوع پرداخته شود.

پلی مورفیسم در پایتون

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

پلی مورفیسم با تابع و اشیا در پایتون

می‌توان تابعی را ایجاد کرد که قابلیت دریافت هر شیئی را دارد و چندریختی را امکان‌پذیر می‌سازد. بهتر است برای درک بهتر، مثالی ارائه شود. در این مثال، تابعی به نام func()  ایجاد شده است که شیئی را با نام obj   دریافت خواهد کرد. سپس باید عملکردی را برای این تابع تعریف کرد که در آن از شی obj استفاده شده است. می‌توان نام متدها را type()   و color()   انتخاب کرد که هر یک از آن‌ها در دو کلاس Tomato و Apple تعریف شده‌اند. حالا می‌توان نمونه‌سازی‌هایی را هم از کلاس‌های Tomato و هم Apple انجام داد:

1class Tomato(): 
2     def type(self): 
3       print("Vegetable") 
4     def color(self):
5       print("Red") 
6class Apple(): 
7     def type(self): 
8       print("Fruit") 
9     def color(self): 
10       print("Red") 
11      
12def func(obj): 
13       obj.type() 
14       obj.color()
15        
16obj_tomato = Tomato() 
17obj_apple = Apple() 
18func(obj_tomato) 
19func(obj_apple)

به این ترتیب، خروجی کدهای فوق به صورت زیر خواهد بود:

Vegetable
Red
Fruit
Red

پلی مورفیسم با متدهای کلاس در پایتون

پایتون از نوع کلاس‌های مختلف به شکل یکسان استفاده می‌کند. در اینجا باید یک حلقه for ایجاد شود که به وسیله آن از طریق تاپلی از اشیا تکرار می‌شود. سپس، باید متدها را بدون نگرانی داشتن در مورد اینکه هر شی از چه نوع کلاسی است، فراخوانی کرد. اینطور فرض می‌شود که این متدها در واقع در همه کلاس‌ها وجود دارند و تعریف شده‌اند. در ادامه مثالی برای نمایش پلی مورفیسم با کلاس در پایتون ارائه شده است:

1class India():
2     def capital(self):
3       print("New Delhi")
4 
5     def language(self):
6       print("Hindi and English")
7 
8class USA():
9     def capital(self):
10       print("Washington, D.C.")
11 
12     def language(self):
13       print("English")
14 
15obj_ind = India()
16obj_usa = USA()
17for country in (obj_ind, obj_usa):
18country.capital()
19country.language()

خروجی کدهای فوق به صورت زیر است:

New Delhi
Hindi and English
Washington, D.C.
English

پلی مورفیسم با ارث بری در پایتون

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

این کار اغلب در مواردی انجام می‌شود که متُد به ارث برده شده از کلاس والد با کلاس فرزند سازگار نباشد. این فرایند پیاده‌سازی مجدد یک متُد در کلاس فرزند را بازنویسی متُد (Method Overriding) می‌نامند که پیش‌تر هم به آن اشاره شد. در ادامه مثالی ارائه شده است که پلی مورفیسم با ارث‌بری در پایتون را نشان می‌دهد:

1class Bird:
2     def intro(self):
3       print("There are different types of birds")
4 
5     def flight(self):
6       print("Most of the birds can fly but some cannot")
7 
8class parrot(Bird):
9     def flight(self):
10       print("Parrots can fly")
11 
12class penguin(Bird):
13     def flight(self):
14       print("Penguins do not fly")
15 
16obj_bird = Bird()
17obj_parr = parrot()
18obj_peng = penguin()
19 
20obj_bird.intro()
21obj_bird.flight()
22 
23obj_parr.intro()
24obj_parr.flight()
25 
26obj_peng.intro()
27obj_peng.flight()

خروجی کدهای فوق به صورت زیر است:

There are different types of birds
Most of the birds can fly but some cannot
There are different types of bird
Parrots can fly
There are many types of birds
Penguins do not fly

به این ترتیب، انواع پلی مورفیسم در پایتون نیز شرح داده شد. حال در ادامه به پلی مورفیسم در C++‎ پرداخته شده است.

پلی مورفیسم در C++‎

در C++‎ پلی مورفیسم به طور کلی به دو نوع مختلف تقسیم می‌شود:

  • پلی مورفیسم زمان کامپایل
  • پلی مورفیسم زمان اجرا
انواع پلی مورفیسم در سی پلاس پلاس

پلی مورفیسم زمان کامپایل در C++‎

این نوع از پلی مورفیسم به وسیله «سربارگذاری تابع» (Function Overloading) یا «سربارگذاری عملگر» (Operator Overloading) حاصل می‌شود. در ادامه به هر یک این دو نوع از پلی مورفیسم زمان کامپایل در C++‎ پرداخته شده است.

سربارگذاری تابع در C++‎

زمانی که چندین تابع با نام یکسان، اما با پارامترهای متفاوت وجود دارد، آنگاه گفته می‌شود که این توابع سربارگذاری شده‌اند. سربارگذاری توابع را می‌توان به وسیله تغییر دادن تعداد آرگومان‌ها یا تغییر در نوع‌ داده این آرگومان‌ها انجام داد. در ادامه برنامه‌ای به زبان C++‎ برای سربارگذاری تابع آمده است:

1// C++ program for function overloading
2#include <bits/stdc++.h>
3  
4using namespace std;
5class Geeks
6{
7    public:
8      
9    // function with 1 int parameter
10    void func(int x)
11    {
12        cout << "value of x is " << x << endl;
13    }
14      
15    // function with same name but 1 double parameter
16    void func(double x)
17    {
18        cout << "value of x is " << x << endl;
19    }
20      
21    // function with same name and 2 int parameters
22    void func(int x, int y)
23    {
24        cout << "value of x and y is " << x << ", " << y << endl;
25    }
26};
27  
28int main() {
29      
30    Geeks obj1;
31      
32    // Which function is called will depend on the parameters passed
33    // The first 'func' is called 
34    obj1.func(7);
35      
36    // The second 'func' is called
37    obj1.func(9.132);
38      
39    // The third 'func' is called
40    obj1.func(85,64);
41    return 0;
42} 

خروجی کدهای فوق به صورت زیر است:

value of x is 7
value of x is 9.132
value of x and y is 85, 64

در مثال بالا، یک تابع واحد به نام func   در سه وضعیت مختلف به گونه‌ای متفاوت عمل می‌کند که این خصیصه‌ای چندریختی است.

سربارگذاری عملگر در C++‎

علاوه بر توابع، امکان سربارگذاری عملگرها در C++‎ هم وجود دارد. برای مثال، می‌توان از عملگر به اضافه (‘+’) برای ادغام دو رشته در C++‎ استفاده کرد. می‌دانیم که این عملگر برای جمع به کار گرفته می‌شود که وظیفه آن اضافه کردن دو عملگر است. بنابراین، وقتی که یک عملگر به اضافه بین دو عملوند از نوع صحیح قرار می‌گیرد آن دو عملوند را با هم جمع می‌کند. اما وقتی این عملگر بین دو عملوند از نوع رشته‌ای قرار می‌گیرد، دو رشته با هم ادغام یا در واقع الصاق می‌شوند. در ادامه مثالی برای این حالت ارائه شده است:

1
2// CPP program to illustrate
3// Operator Overloading
4#include<iostream>
5using namespace std;
6   
7class Complex {
8private:
9    int real, imag;
10public:
11    Complex(int r = 0, int i =0)  {real = r;   imag = i;}
12       
13    // This is automatically called when '+' is used with
14    // between two Complex objects
15    Complex operator + (Complex const &obj) {
16         Complex res;
17         res.real = real + obj.real;
18         res.imag = imag + obj.imag;
19         return res;
20    }
21    void print() { cout << real << " + i" << imag << endl; }
22};
23   
24int main()
25{
26    Complex c1(10, 5), c2(2, 4);
27    Complex c3 = c1 + c2; // An example call to "operator+"
28    c3.print();
29}

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

12 + i9

در مثال فوق، عملگر «+» در C++‎ سربارگذاری شده است. عملگر به اضافه یک عملگر جمع است و می‌تواند دو عدد را با هم جمع کند (صحیح یا ممیز شناور) اما در این مثال عملگر برای اجرای عملیات جمع دو عدد موهومی یا مختلط مورد استفاده قرار گرفته است.

پلی مورفیسم زمان اجرا در C++‎

این نوع از چندریختی یا پلی مورفیسم در برنامه نویسی C++‎ و برخی از سایر زبان‌ها از طریق بازنویسی تابع (Function Overriding) انجام می‌شود. بنابراین در ادامه به شرح بازنویسی تابع در C++‎ پرداخته شده است.

بازنویسی تابع در C++‎

بازنویسی تابع از طرف دیگر زمانی اتفاق می‌افتد که یک کلاس مشتق شده دارای تعریفی برای یکی از تابع‌های عضو کلاس پایه باشد. در این شرایط گفته می‌شود که آن تابع پایه بازنویسی شده است. در ادامه مثالی از یک برنامه C++‎ برای بازنویسی تابع ارائه شده است:

1// C++ program for function overriding
2  
3#include <bits/stdc++.h>
4using namespace std;
5  
6class base
7{
8public:
9    virtual void print ()
10    { cout<< "print base class" <<endl; }
11   
12    void show ()
13    { cout<< "show base class" <<endl; }
14};
15   
16class derived:public base
17{
18public:
19    void print () //print () is already virtual function in derived class, we could also declared as virtual void print () explicitly
20    { cout<< "print derived class" <<endl; }
21   
22    void show ()
23    { cout<< "show derived class" <<endl; }
24};
25  
26//main function
27int main() 
28{
29    base *bptr;
30    derived d;
31    bptr = &d;
32       
33    //virtual function, binded at runtime (Runtime polymorphism)
34    bptr->print(); 
35       
36    // Non-virtual function, binded at compile time
37    bptr->show(); 
38  
39    return 0;
40} 

خروجی مثال فوق در ادامه آمده است:

print derived class
show base class

جمع‌بندی

به بیان ساده، چندریختی یا پلی مورفیسم (Polymorphism) در برنامه نویسی، استفاده از یک بلوک کد و تغییر «نسخه» آن بلوک کد، بر اساس نوع ورودی‌ها است. اصطلاح پلی مورفیسم یا چندریختی در برنامه نویسی و علوم کامپیوتر به این معنا است که می‌توان به اشیایی با انواع مختلف از طریق رابط و واسطی یکسان دسترسی داشت. پلی مورفیسم انواع مختلفی در برنامه نویسی دارد که به ‌طور کلی می‌توان آن‌ها را در ۴ دسته مختلف قرار داد. چندریختی به لحاظ اجرا به دو دسته کلی پلی مورفیسم زمان اجرا و چندریختی زمان کامپایل تقسیم می‌شود.

در این مقاله سعی شد تا حد امکان کلیه مباحث و مفهوم‌های مربوط به پلی مورفیسم در برنامه نویسی شرح داده شوند و این قابلیت در تعدادی از زبان‌های برنامه نویسی مطرح و پر استفاده نیز مورد بررسی قرار گرفت. علاوه بر این، برای انواع پلی مورفیسم مثال‌های متعددی در این مقاله برای زبان‌های برنامه نویسی مختلف ارائه شدند.

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
StackifyBMC BlogsTutorialspointIAmDev Grant YoutubeMicrosoft DocsGeeksforGeeks
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *