یک موضوع مهم در برنامه نویسی Polymorphism است و در این جلسه ما به بررسی چندریختی یا Polymorphism در ++C خواهیم پرداخت. واژه چندریختی به معنی داشتن چندین صورت است. معمولاً، چندریختی در شرایطی اتفاق میافتد که زنجیرهای از کلاسها از طریق وراثت به هم مربوط شدهاند.
چندریختی در ++C یعنی اینکه فراخوانی یک تابع عضو، بسته به نوع شی فراخواننده آن، میتواند منجر به اجرای توابع مختلفی شود.
مثال زیر را درنظر بگیرید که در آن دو کلاس از یک کلاس پایه مشتق شدهاند.
#include <iostream> using namespace std; class Shape { protected: int width, height; public: Shape( int a = 0, int b = 0){ width = a; height = b; } int area() { cout << "Parent class area :" <<endl; return 0; } }; class Rectangle: public Shape { public: Rectangle( int a = 0, int b = 0):Shape(a, b) { } int area () { cout << "Rectangle class area :" <<endl; return (width * height); } }; class Triangle: public Shape { public: Triangle( int a = 0, int b = 0):Shape(a, b) { } int area () { cout << "Triangle class area :" <<endl; return (width * height / 2); } }; // Main function for the program int main() { Shape *shape; Rectangle rec(10,7); Triangle tri(10,5); // store the address of Rectangle shape = &rec; // call rectangle area. shape->area(); // store the address of Triangle shape = &tri; // call triangle area. shape->area(); return 0; }
با اجرای این کد، خروجی زیر نتیجه میشود.
Parent class area : Parent class area :
علت این خروجی نادرست این است که برای فراخوانی تابع ()area، کامپایلر از ابتدا نسخه تابع در کلاس پایه را انتخاب کرده است. به این حالت وضوح ایستا (static resolution)، فراخوانی تابع یا اتصال ایستا (static linkage) گفته میشود، تابع پیش از فراخوانی قطعی (fixed) شده است. به این حالت همچنین اتصال اولیه (early binding) نیز گفته میشود زیرا تابع ()area در زمان کامپایل برنامه تعیین شده است.
اما حالا، اجازه دهید یک تغییر کوچک در برنامه ایجاد کرده و پیش از اعلان تابع ()area در کلاس Shape کلیدواژه virtual را قرار دهیم.
class Shape { protected: int width, height; public: Shape( int a = 0, int b = 0) { width = a; height = b; } virtual int area() { cout << "Parent class area :" <<endl; return 0; } };
بعد از اعمال این تغییر جزئی و اجرای کد، خروجی زیر حاصل میشود.
Rectangle class area Triangle class area
اینبار، کامپایلر به جای نوع اشارهگر به محتوای آن نگاه میکند. بنابراین، از آنجایی که آدرس اشیا کلاسهای tri و rec در shape* ذخیره میشود، تابع ()area مربوطه فراخوانی میشود.
همانطور که میبینید، هر کدام از کلاسهای فرزند (child class) پیادهسازی خاص خود را برای تابع ()area دارند. این شکل عمومی کاربرد چندریختی است. شما چند کلاس مختلف با یک تابع با نام و پارامترهای یکسان، اما پیادهسازیهای متفاوت خواهید داشت.
تابع مجازی (Virtual Function)
یک تابع مجازی (Virtual) تابعی از کلاس پایه است که با کلیدواژه virtual اعلان میشود. وجود یک تابع مجازی در کلاس پایه و یک نسخه متفاوت از آن در کلاس مشتق شده، به کامپایلر این نشانی را میدهد که برای این تابع از اتصال ایستا استفاده نکند.
آنچه مطلوب ماست انتخاب تابع در هر نقطه از برنامه، براساس نوع شی فراخوانده شده است. به این عملیات اتصال دینامیک (dynamic linkage) یا اتصال متاخر (late binding) گفته میشود.
توابع مجازی محض (Pure Virtual Functions)
میتوان یک تابع مجازی در کلاس پایه را به گونهای تعریف کرد که در خود کلاس پایه هیچ تعریف معناداری نداشته باشد اما در توابع مشتق شده قابل تعریف مجدد باشد.
تابع مجازی ()area را در کلاس پایه به صورت زیر تغییر میدهیم.
class Shape { protected: int width, height; public: Shape(int a = 0, int b = 0) { width = a; height = b; } // pure virtual function virtual int area() = 0; };
عبارت 0 = به کامپایلر اعلام میکند که این تابع هیچ بدنهای ندارد. این تابع، تابع مجازی محض (pure virtual function) نامیده میشود.
منبع: ترجمه از سایت tutorialspoint.com
در جلسه بعدی آموزش ++C با ما همراه باشید.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.
مختصر و مفید بود ممنون کد مثال هم کلیر و قابل فهم بود