PDA

View Full Version : سوال: توابع مجازی



mohsen_nikoei
شنبه 21 آذر 1394, 01:46 صبح
سلام...کاربرد تابع مجازی کجاست؟ میگن میتونی تابع مجازی رو تو کلاس پایه تعریف کنی و کلاسای مشتق شده اون رو مختص خودشون تعریف کنن... ولی چه لزومی به اینکار هست ما میتونیم اون تابع رو بصورت عادی هم تو کلاس پایه و هم مشتق تعریف کنیم و بصورت عادی استفاده کنیم.. درسته وقتی که از اشاره گر کلاس پایه که به شی از کلاس مشتق اشاره میکنه استفاده کنیم اتوماتیک تشخیص میده از کدوم تابع استفاده کنه ولی ایا توابع مجازی فقط برای اینه که وقتی از اشاره گر استفاده کردیم اینکار رو بکنه؟ اگر اره پس برتریش نسبت به روش اول چیه کجا میتونیم از توابع مجازی استفاده کنیم که با حالت عادی نمیشه با تشکر

pswin.pooya
شنبه 21 آذر 1394, 18:40 عصر
سلام...کاربرد تابع مجازی کجاست؟ میگن میتونی تابع مجازی رو تو کلاس پایه تعریف کنی و کلاسای مشتق شده اون رو مختص خودشون تعریف کنن... ولی چه لزومی به اینکار هست ما میتونیم اون تابع رو بصورت عادی هم تو کلاس پایه و هم مشتق تعریف کنیم و بصورت عادی استفاده کنیم.. درسته وقتی که از اشاره گر کلاس پایه که به شی از کلاس مشتق اشاره میکنه استفاده کنیم اتوماتیک تشخیص میده از کدوم تابع استفاده کنه ولی ایا توابع مجازی فقط برای اینه که وقتی از اشاره گر استفاده کردیم اینکار رو بکنه؟ اگر اره پس برتریش نسبت به روش اول چیه کجا میتونیم از توابع مجازی استفاده کنیم که با حالت عادی نمیشه با تشکر

خود اینم خیلی مهمه. این روش به شما امکان میده که کلاسهای مختلفی با کاربردهای متفاوت داشته باشید که interface یکسان داشته باشند. داخل زبانهای دیگه مثل C# و یا جاوا بجاش interface تعریف شده که کارایی کمتری از توابع مجازی C++ داره. منظورم اینه که شما نمی تونید برای اینترفیسها تابع عادی و یا حتی کد پیش فرض داشته باشید.

توابع مجازی می تونن کاربرد یک تابع اصلی توی کلاس پایه رو هم تغییر بدن که خیلی مهم هست.

البته بجای تابع بهتره از متد استفاده کنید.

حامد مصافی
شنبه 21 آذر 1394, 19:51 عصر
توابع مجازی در واقع چیزی بیش از اینها هستند. اعلانات مجازی مستقیما در vtable نوشته میشن. تفاوت دو حالتی که فرمودید زمانی مشخص می‌شود که کلاس شما از نوع پایه اعلان و از نوع مشتق‌شده مقداردهی شود. برای مثال در این کد:
#include <iostream>

using namespace std;


class Base{
public:
string foo(){
return "Base::foo()";
}


virtual string bar(){
return "Base::bar()";
}
};


class Delivered : public Base{
public:
string foo(){
return "Delivered::foo()";
}


virtual string bar(){
return "Delivered::bar()";
}
};


int main()
{
Base *obj = new Delivered;


cout << "Calling foo; " << obj->foo() << endl;
cout << "Calling bar; " << obj->bar() << endl;
return 0;
}




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

Calling foo; Base::foo()
Calling bar; Delivered::bar()

همانطور که مشخص است اعلان virtual باعث می‌شود که تابع bar در vtable نوشته شده و هنگام فراخوانی به درستی فراخوانده شود. اما متد foo در یک اشتباه منطقی از کلاس پایه فراخوانده شده است که احتمالا نباید این‌گونه باشد.

mohsen_nikoei
یک شنبه 22 آذر 1394, 21:33 عصر
با تشکر..حالا اگر در همین برنامه ای که شما نوشتید ما بجای اینکه متد foo و bar رو vrtual تعریف کنیم اونارو معمولی تعریف میکردیم و بجای استفاده از اشاره گر کلاس پایه از شی تعریف شده توسط کلاس مشتق استفاده میکردیم(obj.foo()) باز هم همین نتیجه رو داشتیم پس چه لزومی داره از virtual استفاده کنیم؟...... عذر خواهی میکنم من الان دو روزه تو سایت ها دنبال مفهوم و کاربرد دقیق تابع مجازی میگردم ولی به نتیجه مناسبی نرسیدم...

rahnema1
دوشنبه 23 آذر 1394, 22:57 عصر
سلام
اگه می خواهید با کاربرد شیء گرایی و تابع مجازی آشنا بشید پیشنهاد می کنم در خصوص «الگوهای طراحی» یا design patterns در ++c تحقیق کنید تو اینترنت مطالب خیلی خوب با مثال پیدا می شه
مثل اینجا (https://en.wikibooks.org/wiki/C++_Programming/Code/Design_Patterns) که یکی از منابع هست و منابع دیگه
حالا یه مثال کوچک هم من در اینجا (http://barnamenevis.org/showthread.php?459856) زده ام

mohsen_nikoei
چهارشنبه 25 آذر 1394, 10:24 صبح
توابع مجازی در واقع چیزی بیش از اینها هستند. اعلانات مجازی مستقیما در vtable نوشته میشن. تفاوت دو حالتی که فرمودید زمانی مشخص می‌شود که کلاس شما از نوع پایه اعلان و از نوع مشتق‌شده مقداردهی شود. برای مثال در این کد:
#include <iostream>

using namespace std;


class Base{
public:
string foo(){
return "Base::foo()";
}


virtual string bar(){
return "Base::bar()";
}
};


class Delivered : public Base{
public:
string foo(){
return "Delivered::foo()";
}


virtual string bar(){
return "Delivered::bar()";
}
};


int main()
{
Base *obj = new Delivered;


cout << "Calling foo; " << obj->foo() << endl;
cout << "Calling bar; " << obj->bar() << endl;
return 0;
}




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

Calling foo; Base::foo()
Calling bar; Delivered::bar()

همانطور که مشخص است اعلان virtual باعث می‌شود که تابع bar در vtable نوشته شده و هنگام فراخوانی به درستی فراخوانده شود. اما متد foo در یک اشتباه منطقی از کلاس پایه فراخوانده شده است که احتمالا نباید این‌گونه باشد.



با تشکر..حالا اگر در همین برنامه ای که شما نوشتید ما بجای اینکه متد foo و bar رو vrtual تعریف کنیم اونارو معمولی تعریف میکردیم و بجای استفاده از اشاره گر کلاس پایه از شی تعریف شده توسط کلاس مشتق استفاده میکردیم(obj.foo()) باز هم همین نتیجه رو داشتیم پس چه لزومی داره از virtual استفاده کنیم؟...... عذر خواهی میکنم من الان دو روزه تو سایت ها دنبال مفهوم و کاربرد دقیق تابع مجازی میگردم ولی به نتیجه مناسبی نرسیدم...

negative60
چهارشنبه 25 آذر 1394, 15:39 عصر
الزامی نيست, بدون استفاده از توابع مجازی و با استفاده از اشاره گر ها هم ميشه کار کرد اما هرچه پروژها بزرگتر ميشوند و تعداد کلاس ها با کاربرد های مختلف افزايش پيدا ميکنه فوايد توابع مجازی و مشتق سازی بيشتر مشخص ميشه
اين نمودار رو ببينيد که از روش مشتق سازی استفاده شده
137477

فرض کنيد برای تمام اين کلاس ها قرار بود اشاره گر تعريف کنيم, به اين شکل ميشد
137478

به غير از اينکه بايد برای تمام کلاس ها اشاره گر تعريف کنيم مشخص نيست کدام کلاس چه کلاس هایی مشتق شده اگر خودتون چند ماه بعد به اين پروژه نگاه کنيد متوجه نميشيد چه کار کرديد بايد بشينيد دوباره تمام کلاس ها رو برسی کنيد اين روش درک و فهم از پروژه رو پاين مياره حالا اگر پروژه گروهی هم باشه باز کار پيچيده تر ميشه

حامد مصافی
چهارشنبه 25 آذر 1394, 17:17 عصر
با تشکر..حالا اگر در همین برنامه ای که شما نوشتید ما بجای اینکه متد foo و bar رو vrtual تعریف کنیم اونارو معمولی تعریف میکردیم و بجای استفاده از اشاره گر کلاس پایه از شی تعریف شده توسط کلاس مشتق استفاده میکردیم(obj.foo()) باز هم همین نتیجه رو داشتیم پس چه لزومی داره از virtual استفاده کنیم؟...... عذر خواهی میکنم من الان دو روزه تو سایت ها دنبال مفهوم و کاربرد دقیق تابع مجازی میگردم ولی به نتیجه مناسبی نرسیدم...
معمولاً در جایی که ارث‌بری و چند ریختی و سایر مفهومات شی گرایی کاربرد داره همیشه نمی‌تونیم مطمئن باشیم که اشاره‌گر ما به نوع خود شی خواهد بود.
برای مثال فرض کنید یک تابع داریم برای تغییر عنوان یک کنترل نمایش داده شده روی فرم. این تابع نمیدونه که کنترلی که باید باهاش کار کنه از چه نوعیه (CButton, CEdit و ...) به همین دلیل تابع ما به طور ساده و همه‌جانبه یک اشاره‌گر از نوع CControl دریافت می‌کنه حالا ممکنه در جایی CButton بهش پاس داده بشه و در جایی دیگر CLabel. تایع ما هم فقط متد setText روی شی CControl رو فراخوانی می‌کنه. اینجاست که اهمیت توابع مجازی آشکار میشه. چون اگر setText به صورت virtual نباشه تایع ما درست کار نخواهد کرد.