PDA

View Full Version : Run-time Compile-time



Shyan Javani
جمعه 25 تیر 1389, 13:08 عصر
علیکم السّلام

ممکنه بگید لابد میخواد بپرسه فرق اینا چیه.خب سوالم شبیه همینه.من میدونم فرق اینا چیه ولی نمیفهمم این فرق چه ربطی به polymorphism داره.خواهش میکنم یکی اینو به من توضیح بده.تو اینترنت گشتم ولی چیزایی که پیدا کردم نتونستن شیرفهمم کنن.

ممنون

PC2st
جمعه 25 تیر 1389, 13:40 عصر
چون برای استفاده از چندریختی (polymorphism)، از توابع مجازی (virtual functions) استفاده می‌شه و برای تشخیص استفادهٔ صحیح از این توابع، از RTTI (مخفف run-time type information) استفاده می‌شه و RTTI هم در زمان اجرا است.

Shyan Javani
شنبه 26 تیر 1389, 08:32 صبح
از توضیحات شما متشکرم چون کاملا کاربردی و موثر بودن و من اگه اینا رو نمیدونستم به خوبی یادشون میگرفتم.اما سوال من یه چیز دیگه است.
میدونید که زمان کامپایل(که فقط یه بار اتفاق میفته)یعنی وقتی کد C++‎ به اسمبلی ترجمه میشه.زمان اجرا یعنی وقتی که کد به زبان اسمبلی یا زبان ماشین اجرا میشه.میخواستم بگم که این چیزهایی که بهشون میگن Run time polymorphism چه ویژگیهایی دارن که باعث میشه بهشون این اسم رو بدن؟در مورد compile time polymorphism چی؟
ممنون

PC2st
شنبه 26 تیر 1389, 12:02 عصر
compile time polymorphism (به اختصار در اینجا ctp می‌نویسم) با run time polymorphism (به اختصار در اینجا rtp می‌نویسم) متفاوت است از این لحاظ که ctp در زمان کامپایل از چندریختی بودن اطمینان حاصل می‌کند اما rtp در زمان اجرا از چندریختی بودن اطمینان حاصل می‌کند. توجه کنید که اگر این اطمینان وجود نداشته باشد، پس نمی‌توان آنها را به کار بست.
ctp منظور برای همان سربارگذاری توابع (function overloading) است، البته templateها در زبان ++C هم به نوعی می‌توانند مفهوم چندریختی را بر روی کلاس‌ها اعمال کنند.
rtp هم که همان چندریختی در مفهوم شیئ‌گرایی است و به این لحاظ rtp گفته می‌شود چون در زمان اجرا این اطمینان از نحوهٔ استفادهٔ آنها حاصل می‌شود (در زمان کامپایل نمی‌توان به این اطمینان دست یافت).

Shyan Javani
شنبه 26 تیر 1389, 23:07 عصر
در زمان کامپایل نمی‌توان به این اطمینان دست یافت

آها الان فهمیدم از اول باید چی میپرسیدم.چرا CTP در زمان کامپایل میشه ولی RTP نمیشه.اینو هیچ حا توضیح نداده بودن.البته درک میکنم که دیگه از زمینه آموزش C++ خارج میشه و شاید خیلی تخصصی بشه ولی حس میکنم با ندونستن این چیز مهمی رو از دست دادم و شی گرایی رو ناقص درک کردم.

ممنون

eshpilen
یک شنبه 27 تیر 1389, 00:00 صبح
به این کد دقت کنید :

#include <iostream>
using namespace std;

struct A
{
virtual char* Foo (void) { return "Class A"; }
}*a;

struct B : A
{
virtual char* Foo (void) { return "Class B"; }
};

void Test (B* b)
{
cout<<"B* b is : "<<typeid(*b).name()<<endl;

b = dynamic_cast<B*>(b);

if(b){
cout<<"Succeed"<<endl;
}
else
cout<<"Failed"<<endl;
}

int main (void)
{
a = new A;
Test((B*)a);

getchar();
return 0;
}
شما نمیتونید مطما باشید که همیشه پارامتری که به تابع Test فرستاده میشود یک اشاره گر از یک B واقعی هست. یعنی ممکن است ریخت واقعی اشاره گری که به Test فرستاده میشود از یک نوع دیگه باشد.
برای همین شما باید این اطمینان رو با استفاده از dynamic_cast بدست بیارید.
دلیلش هم اینه که dynamic_cast در زمان اجرا (Run-Time) با استفاده از RTTI میتونه دقیقا نوع یک اشاره گر رو بررسی کنه و مانع از Cast های اشتباه بشه.
برای استفاده از dynamic_cast و شما باید قابلیت RTTI رو در کامایلرتون فعال کنید که به صورت پیش فرض در بیشتر کامپایلر ها فعال هست.
مثلا در کد بالا اشاره گر a به تابع Test فرستاده میشه ، و تابع Test با استفاده از dynamic_cast متوجه میشه که پارامتر فرستاده شده یک B واقعی نیست.
حالا اگر شما اشاره گر a رو به این صورت ;a = new B ایجاد کنی و به تابع تست ارسال کنی ، تابع تست متوجه میشه که این اشاره گر یک B واقعی است.

درکل بعضی از اشاره گرها در طول برنامه به ریخت های متفاوتی تبدیل میشوند (Poylymorphism) که شما با استفاده از dynamic_cast و typeid میتونید ریخت حال حاضر این اشاره گر ها رو در زمان Run-Time بررسی کنید.

خروجی این برنامه برای من این بود:


B* b is : 1A
Succeed
درسته؟ بنظرم مطابق انتظار نیست :متفکر:

eshpilen
یک شنبه 27 تیر 1389, 00:03 صبح
هان فهمیدم! بنظرم شما باید کد رو جور دیگه ای مینوشتی. چون اول خودت cast معمولی به B کردی موقع پاس کردن به تابع Test که باعث میشه تابع مربوطه a رو واقعا از نوع B ببینه.

کد درستش بنظرم شبیه این میشه:


#include <iostream>
#include <typeinfo>

using namespace std;

struct A
{
virtual char* Foo (void) { return "Class A"; }
}*a;

struct B : A
{
virtual char* Foo (void) { return "Class B"; }
};

void Test (A* b)
{
cout<<"B* b is : "<<typeid(*b).name()<<endl;

b = dynamic_cast<B*>(b);

if(b){
cout<<"Succeed"<<endl;
}
else
cout<<"Failed"<<endl;
}

int main (void)
{
a = new A;
Test(a);


return 0;
}

eshpilen
یک شنبه 27 تیر 1389, 00:07 صبح
یه سوال!
در 1A اون عدد 1 به چه معناست؟

PC2st
یک شنبه 27 تیر 1389, 00:55 صبح
یه سوال!
در 1A اون عدد 1 به چه معناست؟ معنای خاصی نداره. :لبخند: در مورد تولید نام، کامپایلر تصمیم می‌گیرد.

Shyan Javani
یک شنبه 27 تیر 1389, 01:30 صبح
جناب اشپیلن کد شما رو کامپایل کردم خروجیش شد این:


B* b is : 1A
Failed

خب این یه خرده عجیبه چون در کد اولیه ما هنگام فرستادن a به تابع اون رو به B* تبدیل میکنیم و میبینید که تبدیل با موفقیت انجام میشه و برنامه بدون مشکل اجرا میشه و خروجی میشه succeed.یعنی این تبدیل یه تبدیل مجازه.اما اینجا میبینیم که dynamic_cast تبدیل ما رو غیرمجاز میدونه.چرا؟

در ضمن سوال های من رو هم اگه میشه یکی جواب بدید(گفتم که اگه تاپیک منحرف شد(که داره میشه) من بی جواب نمونم)البته با منحرف شدنش مشکلی ندارم چون یاد گرفتن خوبه.

ممنون

eshpilen
یک شنبه 27 تیر 1389, 08:57 صبح
جناب اشپیلن کد شما رو کامپایل کردم خروجیش شد این:


B* b is : 1A
Failed

خب این یه خرده عجیبه چون در کد اولیه ما هنگام فرستادن a به تابع اون رو به B* تبدیل میکنیم و میبینید که تبدیل با موفقیت انجام میشه و برنامه بدون مشکل اجرا میشه و خروجی میشه succeed.یعنی این تبدیل یه تبدیل مجازه.اما اینجا میبینیم که dynamic_cast تبدیل ما رو غیرمجاز میدونه.چرا؟


خب فکر میکنم چون Cast معمولی خودش شعور نداره و هرچی شما بگی دربست گوش میکنه.
اگر بگی این B هست، کامپایلر همین فرض رو قبول میکنه و دیگه همه جا طرف رو B میبینه (حتی اگر سنخیتی با B نداشته باشه).
اما فرق dynamic_cast اینه که با استفاده از اطلاعاتی که در زمان اجرا راجع به ماهیت اشیاء در دسترس داره (RTTI) خودش تصمیم میگیره که تبدیل انجام شده معنا دار و مشروع هست یا نه.


آها الان فهمیدم از اول باید چی میپرسیدم.چرا CTP در زمان کامپایل میشه ولی RTP نمیشه.اینو هیچ حا توضیح نداده بودن.البته درک میکنم که دیگه از زمینه آموزش C++‎ خارج میشه و شاید خیلی تخصصی بشه ولی حس میکنم با ندونستن این چیز مهمی رو از دست دادم و شی گرایی رو ناقص درک کردم.
خب فکر میکنم نیاز به نمونه کدهای عملی باشه.
ولی من نظر خودم رو توضیح میدم شاید گرفتی.
یکسری اشیاء رو چون ما در زمان اجرا و احتمالا بر اساس پارامترهای خارجی (مثل ورودی کاربر) ایجاد و دستکاری میکنیم، ماهیت اونها در زمان کامپایل از پیش مشخص نیست و ممکنه اصلا وجود نداشته باشن که کامپایلر بخواد تصمیمی درموردشون بگیره.
ضمنا حتی اگر کامپایلر تصمیمی برای بعضی اشیاء که در هنگام اجرا به نحوه های مختلفی تفسیر میشن یا تغییر میکنن بگیره، این تصمیمات ثابت خواهند بود و با توجه به پارامترهای زمان اجرا تغییر نمیکنن. بله فکر میکنم کلیتش همین باشه.
امیدوارم دوستان دیگه زحمتش رو بکشن و نمونه کدی چیزی بذارن.

Shyan Javani
یک شنبه 27 تیر 1389, 18:07 عصر
واقعا ازتون ممنونم چون به جواب سوالی که از اول تاپیک رو به خاطرش زده بودم گرفتم.
اما اشپیلن فکرکنم تا حالا خطای زیر رو دیده باشی

Invalid conversion from 'char *' to 'char'
که نشان دهنده شعور تمام و کمال کست معمولیه
پس مسئله هنوز سر جاشه.



خروجی این برنامه برای من این بود:



کد:
B* b is : 1A
Succeed

درسته؟ بنظرم مطابق انتظار نیست :متفکر:


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

eshpilen
یک شنبه 27 تیر 1389, 19:16 عصر
[QUOTE=Shyan Javani;1045026]واقعا ازتون ممنونم چون به جواب سوالی که از اول تاپیک رو به خاطرش زده بودم گرفتم.
اما اشپیلن فکرکنم تا حالا خطای زیر رو دیده باشی

Invalid conversion from 'char *' to 'char'
که نشان دهنده شعور تمام و کمال کست معمولیه
پس مسئله هنوز سر جاشه.

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

Shyan Javani
یک شنبه 27 تیر 1389, 20:49 عصر
کامپایلر شعورش میرسه، از برنامه نویس اونوقت بعیده اینکارا

خب من مبتدی هستم :خجالت:(فکز کنم در مواقعی رفتار مبتدی و بی شعور مثل هم بشه:متفکر:)