PDA

View Full Version : متدهای Abstract



حمیدرضاصادقیان
دوشنبه 07 تیر 1389, 08:24 صبح
سلام.
ما یک کلاس داریم که یک متد Abstract داره.دو کلاس دیگه هم از این کلاس مشتق میکنیم و باید اون متد رو خودمون پیاده سازی کنیم.
حالا برای استفاده هم نمیتونیم یک متغیر کلی از کلاس پایه در نظر بگیریم چون متد فوق پیاده سازی نداره و خطا میگیره.مجبوریم برای هر کلاس بیایم یک متغیر جداگانه تعریف کنیم.
حالا سوال اینجاست چه لزومی داره بیایم متد کلاس Abstract رو به صورت Virtual تعریف کنیم و زیر مجموعه های اونو به صورت Override؟
خوب ما اینکارو برای زمانی انجام میدیم که متد اصلی هم تعریفی داره و ما میخواهیم به جز تعریف خودش یک پیاده سازی دیگه در کلاسهای دیگه داشته باشیم و در صورت لزوم با استفاده از Inherited دستورات متد پایه رو اجرا کنیم.همچنین اگر یک متغیر از کلاس پایه ایجاد کردیم و متد اونو فراخوانی کردیم با توجه به کلاسهای زیر مجموعه ای که بهش پاس دادیم متد مورد نظر ما رو صدا کنه.
ولی این تعریف در یک کلاس انتزاعی به چه دردی میخوره؟
باتشکر

مصطفی ساتکی
دوشنبه 07 تیر 1389, 08:57 صبح
شما گاهی اوقات در کلاس پایه نیاز دارید متدی را فراخوانی کنید که این متد در سطح کلاس پایه کدی ندارد ولی در هر کدام از کلاس های inherited شده دارای کدی می باشد پس اگر این تعریف این متد وجود نداشته باشد این کار امکان پذیر نیست

حمیدرضاصادقیان
دوشنبه 07 تیر 1389, 09:42 صبح
سلام.ممنون.ولی متوجه نشدم.
ببینید به مثال زیر شما توجه کنید.



type
TMyShape = class (TObject)
public
procedure Draw (AnImage: TImage; ABorder: integer); virtual; abstract;
end;
TMyEllipse = class (TMyShape)
public
procedure Draw (AnImage: TImage; AnBorder: integer); override;
end;

TMyRectangle = class (TMyShape)
public
procedure Draw (AnImage: TImage; ABorder: integer); override;
end;

دراینجا چه لزومی داره ما متد Abstract رو به صورت Virtual تعریف کردیم؟

Mahyaa
دوشنبه 07 تیر 1389, 11:06 صبح
ببخشید من سوالتون رو اشتباه متوجه شده بودم!

من خودم همین امروز یک تاپیک برای Virtual باز کردم و داشتم در موردش سرچ میکردم که خوردم به اینجا (http://www.prestwoodboards.com/ASPSuite/KB/document_view.asp?qid=101346&GroupID=)که گفته در Abstract باید حتما مشخص بشه که Virtual تعریف شده یا Dynamic.
اولی در سرعت بهینه شده و دومی در سایز.


قسمت Virtual Abstract versus Dynamic Abstract در لینک داده شده ببینید

مصطفی ساتکی
دوشنبه 07 تیر 1389, 11:47 صبح
من خودم همین امروز یک تاپیک برای Virtual باز کردم و داشتم در موردش سرچ میکردم که خوردم به اینجا (http://www.prestwoodboards.com/ASPSuite/KB/document_view.asp?qid=101346&GroupID=)که گفته در Abstract باید حتما مشخص بشه که Virtual تعریف شده یا Dynamic.
اولی در سرعت بهینه شده و دومی در سایز.
در Delphi win 32 این تعریف میتونه اختیاری باشه چون کامپایلر به شکل پیش فرض اون رو Virtual در نظر میگیره.

قسمت Virtual Abstract versus Dynamic Abstract در لینک داده شده ببینید
قربان بحث ایشون رو virtual و Dynamic بودن متد نیست لزوم بکارگیری شناسه abstract هدف ایشون.
جناب صادقیان در مثالی که بیان کردید کلاس TMyShape بفرض دارای پارامترهایی باشه و به محض تغییر بایستی کلاس مورد نظر کل DC مربوط به خودش رو Refresh کنه در این صورت در رویداد change که در قسمت protected تعریف میشه و از نوع virtual نیز هست شما متد Draw رو فراخوانی میکنید .چون در کلاس inherited شده از این کلاس اگر هم پارامتر جدیدی اضافه بشه باز هم از طریق متد change خودش رو draw یا refresh می کنه.

حمیدرضاصادقیان
دوشنبه 07 تیر 1389, 11:48 صبح
درسته.من اشتباه متوجه شده بودم.کلا برای تعریف Abstract وجود کلمه Virtual یا Dynamic الزامی است.من کلا با وجود این کلمه مشکل داشتم.
ولی وقتی متد Abstract در کلاس Child پیاده سازی نمیشه فقط یک Warning میده که یک متد به صورت Abstract هست.مگر نباید جلوی کامپایل برنامه رو کلا بگیره .؟؟

vcldeveloper
دوشنبه 07 تیر 1389, 14:15 عصر
دراینجا چه لزومی داره ما متد Abstract رو به صورت Virtual تعریف کردیم؟
این که چرا باید این متد virtual باشه، به خاطر پیاده سازی داخلی اون متدها توسط کامپایلر هست. متدهای Abstract باید Virtual باشند، تا در VMT کلاس درج بشند، و کلاس های فرزند بتونند آن را override کنند.

البته میشد این را طوری طراحی کرد که هر وقت کلید واژه abstract درج شد، کامپایلر به طور ضمنی، Virtual بودن آن متد را هم در نظر بگیره. اما اینکه چرا کامپایلر دلفی به صورت ضمنی abstract را virtual فرض نمیکنه، و نیاز داره که برنامه نویس خودش کلید واژه virtual را قید کنه، را من اطلاع ندارم؛ یک دلیلش میتونه این باشه که در دلفی متدهای مجازی می تونند به دو صورت virtual یا dynamic قید بشند، و کامپایلر خواسته دست برنامه نویس را در انتخاب نوع متد مجازی باز بزاره، اینطوری برنامه نویس میتونه تصمیم بگیره که متد abstract مربوطه virtual باشه یا dynamic.

Virtual و Dynamic از نظر کاربرد تفاوتی ندارند، ولی در پیاده سازی با هم متفاوت هستند، و در شرایط عادی، virtual از dynamic کارآمدتر هست، ولی dynamic در شرایط خاصی کارایی بهتری داره، و در VCL از هر دو به شکل گسترده استفاده شده. البته تفاوت در کارایی جزئی هست.


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


Obj : TMyShape;
...
Obj := TMyEllipse.Create;

به عنوان نمونه ایی از این رفتار، می تونید به کلاس TStrings و استفاده از آن در کلاس های دیگه مراجعه کنید. کلاس TStrings تعدادی متد abstract داره، و کلاس های فرزند آن، مثل TStringList، این متدها را پیاده سازی می کنند. کلاس های مختلف از TStrings به عنوان خصوصیت، یا پارامترهای متدهای خود، استفاده می کنند، ولی اشیائی که ساخته میشند، معمولا TStringList هستند. مثلا خصوصیت Items از TListBox به صورت TStrings تعریف شده، اما در هنگام پیاده سازی، یک شی TStringList ساخته میشه و استفاده میشه. اینطوری می توان از هر یک از کلاس های فرزند TStrings استفاده کرد.

شما می تونید حتی از کلاس پایه TMyShape هم شی ایجاد کنید، ولی بابت آن Compiler Warning دریافت می کنید، و اگر یکی از متدهای abstract این شی را فراخوانی کنید، Abstract Error دریافت می کنید.

علت استفاده از متدهای Abstract هم الزامی کردن پیاده سازی متدهای مربوطه توسط کلاس های فرزند هست؛ یعنی طراح کلاس پایه، طراحانی که کلاس های خود را بر پایه کلاس وی طراحی می کنند، را ملزم به پیاده سازی این متدها میکنه. در حالی که در صورت استفاده تنها از متدهای virtual یا dynamic، الزامی به پیاده سازی این متدها نبود، حتی اگر سورس کد کلاس پایه در دسترس نبود، یا مستنداتی برای آن کلاس ارائه نمی شد، برنامه نویسان متوجه الزامی بودن پیاده سازی آن متدها نمی شدند، و فقط در زمان اجرای برنامه، و برخورد با خطاهای مختلف، ممکن بود که متوجه شوند که این متدها نیاز به پیاده سازی دارند. اما با وجود متدهای abstract، حتی بدون در دست داشتن سورس کد کلاس پایه، یا مستندات آن، برنامه نویس در هنگام کامپایل، اگر از کلاس پایه شی ایی ایجاد کنه، Warning دریافت میکنه، و متوجه میشه که باید این متد پیاده سازی نشده. در کلاس های فرزند هم اگر این متد را پیاده سازی نکنه، در هنگام اجرا، Abstract Error دریافت میکنه، و متوجه میشه که باید خودش این متد را پیاده سازی کنه. البته اگر از Interface به جای Abstract Class استفاده بشه، اصلا تا زمانی که کلاس مربوطه Interface مورد نظر را پیاده سازی نکنه، برنامه کامپایل نمیشه! البته کاربرد Interface عینا مشابه Abstract Class نیست.

همچنین، در صورت استفاده از virtual و dynamic به تنهایی، کلاس پایه میتونه بخشی از کد را که بین فرزندان مشترک هست، خودش درج کنه، اما در صورت استفاده از abstract، دیگه کد مشترک پیش فرضی بین کلاس های فرزند وجود نداره، و باید کل عملیات اون متد توسط هر یک از فرزندان پیاده سازی بشه.

حمیدرضاصادقیان
دوشنبه 07 تیر 1389, 14:29 عصر
علی جان بابت توضیحات کاملت ممنون.


Virtual و Dynamic از نظر کاربرد تفاوتی ندارند، ولی در پیاده سازی با هم متفاوت هستند، و در شرایط عادی، virtual از dynamic کارآمدتر هست، ولی dynamic در شرایط خاصی کارایی بهتری داره، و در VCL از هر دو به شکل گسترده استفاده شده. البته تفاوت در کارایی جزئی هست.


میشه در این مورد بیشتر توضیح بدی. در چه شرایطی نیاز به استفاده از Dynamic هست و در چه شرایطی باید از Virtual استفاده کرد.؟ عمده تفاوت اینها در چیست؟

باتشکر

vcldeveloper
دوشنبه 07 تیر 1389, 14:40 عصر
عمده تفاوت اینها در چیست؟الان کاملا خاطرم نیست؛ فکر می کنم virtual methods از VMT برای پیدا کردن آدرس متد استفاده می کنند، ولی Dynamic Methods از یک سیستم زنجیره ایی. در صورتی که تعداد متدهای مجازی زیاد باشه، برای virtual methods افت کارایی ایجاد نمیشه، اما برای dynamic methods افت صورت میگیره.


در چه شرایطی نیاز به استفاده از Dynamic هست و در چه شرایطی باید از Virtual استفاده کرد؟توصیه معمول این هست که اگر متدی دارید که باید مجازی باشه، ولی احتمال override کردن آن توسط کلاس های فرزند خیلی کم هست، می تونید از dynamic استفاده کنید، در غیر اینصورت از virtual.
البته به طور عمومی virtual بهتر هست، و شما اگر همه متدهای مجازی تان را (چه احتمال override کردن آنها زیاد باشه، چه کم) به صورت virtual تعریف کنید، مشکلی براتون بوجود نمیاد. اگر هم شک دارید که در یک حالت خاص کدام مناسب تر هستند، باز از virtual استفاده کنید. از dynamic فقط زمانی که مطمئن هستید که گزینه مناسب تر هست، استفاده کنید، نه زمانی که حدس می زنید شاید مناسب تر باشه.