با عرض سلام و وقت بخیر خدمت کاربران سایت پی وی لرن ، با یکی دیگر از جلسات دوره کامل آموزش ++C در خدمت شما دوستان هستیم . در بخش قبلی با ساختمان ها در ++C آشنا شدید، در این جلسه قصد داریم به آموزش توابع مجازی در ++C یا Virtual Functions در سی پلاس پلاس بپردازیم.
یک تابع مجازی، تابع عضوی در کلاس پایه می باشد که ما باید آن را در کلاس های مشتق شده پیاده سازی کنیم.
قبل از ورود به جزئیات اجازه دهید تا مثالی بزنیم تا بدانیم چرا از توابع مجازی استفاده می کنیم.
فرض کنید که داریم روی یک بازی کار می کنیم.
ما یک کلاس Weapon ایجاد کردیم و دو کلاس Bomb و Gun را برای بارگذاری ویژگی های مربوطه مشتق کرده ایم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <iostream> using namespace std; class Weapon { public: void loadFeatures() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void loadFeatures() { cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void loadFeatures() { cout << "Loading gun features.\n"; } }; int main() { Weapon *w = new Weapon; Bomb *b = new Bomb; Gun *g = new Gun; w->loadFeatures(); b->loadFeatures(); g->loadFeatures(); return 0; } |
خروجی:
1 2 3 | Loading weapon features. Loading bomb features. Loading gun features. |
ما سه اشاره گر w, b و g را برای کلاس های بالا تعریف کرده ایم و تابع عضو ()loadFeatures را برای هر شی فراخوانی کرده ایم:
1 2 3 | w->loadfeatures(); b->loadFeatures(); g->loadFeatures(); |
با این حال پروژه بازی ما بزرگ و بزرگ تر می شود و تصمیم می گیریم تا یک کلاس loader جداگانه ایجاد کنیم.
این کلاس ویژگی های اضافی هر سلاح را بسته به این که کدام سلاح انتخاب شده است، بارگذاری می کند.
1 2 3 4 5 6 7 8 | class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; |
در زیر کلاس Loader را پیاده سازی کرده ایم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <iostream> using namespace std; class Weapon { public: void features() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void features() { cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void features() { cout << "Loading gun features.\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; } |
خروجی:
1 2 3 | Loading weapon features. Loading weapon features. Loading weapon features. |
پیاده سازی ما درست به نظر می رسد اما weapon features سه بار بارگذاری شده است!
در ابتدا شی Weapon به نام w به شی کلاس Bomb به نام b اشاره می کند. و تلاش می کند تا features شی Bomb را با ارسال آن به تابع ()loadFeatures بارگذاری کند.
به طور مشابه همین کار را با شی Gun انجام داده ایم.
با این حال تابع ()loadFeatures کلاس Loader یک اشاره گر به کلاس Weapon را به عنوان آرگومان می گیرد.
1 | void loadFeatures(Weapon *weapon) |
این همان دلیلی است که waepon features سه بار بارگذاری می شود.
برای حل این موضوع نیاز داریم تا تابع کلاس پایه را با استفاده از کامه کلیدی virtual مجازی کنیم.
1 2 3 4 5 6 | class Weapon { public: virtual void features() { cout << "Loading weapon features.\n"; } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <iostream> using namespace std; class Weapon { public: virtual void features() { cout << "Loading weapon features.\n"; } }; class Bomb : public Weapon { public: void features() { cout << "Loading bomb features.\n"; } }; class Gun : public Weapon { public: void features() { cout << "Loading gun features.\n"; } }; class Loader { public: void loadFeatures(Weapon *weapon) { weapon->features(); } }; int main() { Loader *l = new Loader; Weapon *w; Bomb b; Gun g; w = &b; l->loadFeatures(w); w = &g; l->loadFeatures(w); return 0; } |
خروجی به شکل زیر می باشد:
1 2 3 | Loading weapon features. Loading bomb features. Loading gun features. |
استفاده از توابع مجازی برنامه هایمان را نه تنها تمیز تر بلکه انعطاف پذیر تر نیز می کند.
هدف برنامه نویسی ++C تقسیم پیچیدگی برنامه به بخش های کوچک تر است.
در ++C می توانید یک کلاس انتزاعی (ABstract) ایجاد کنید که نمی توانید هیچ شیی را از آن تعریف کنید.
با این حال می توانید یک کلاس از آن مشتق کنید و اشیا را از ان ایجاد کنید.
کلاسی که دارای تابع مجازی محض (pure) می باشد، یک کلاس انتزاعی است.
تابع مجازی که انتهای آن با ۰= تعریف شود، یک تابع مجازی محض است.
1 2 3 4 5 | class Weapon { public: virtual void features() = 0; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <iostream> using namespace std; // Abstract class class Shape { protected: float l; public: void getData() { cin >> l; } // virtual Function virtual float calculateArea() = 0; }; class Square : public Shape { public: float calculateArea() { return l*l; } }; class Circle : public Shape { public: float calculateArea() { return 3.14*l*l; } }; int main() { Square s; Circle c; cout << "Enter length to calculate the area of a square: "; s.getData(); cout<<"Area of square: " << s.calculateArea(); cout<<"\nEnter radius to calculate the area of a circle: "; c.getData(); cout << "Area of circle: " << c.calculateArea(); return 0; } |
خروجی:
1 2 3 4 | Enter length to calculate the area of a square: 4 Area of square: 16 Enter radius to calculate the area of a circle: 5 Area of circle: 78.5 |
جلسه آموزش توابع مجازی در ++C نیز به پایان رسید.
در جلسه بعد به آموزش الگو ها در ++C خواهیم پرداخت.با ما همراه باشید
Heydar
عزیز من شانسی چشمم خورد به مطلبت |
با اینکه قبلا میدونستم چی به چیه اما جذب سایتت شدم و یه نگاه به این مطلبت انداختم.
از اینکه برای مفاهیم polymorphism از یه مثال جالب استفاده کردید خوشحال شدم(جالب منظورم اینه به نحوی جور دیگه مطلب رو نسبت به بقیه سایتا رسوندید – در قالب مثال دیگه ، بیشتر منظورم اون cast شدن به کلاس پدر هست)