PDA

View Full Version : Override دقیقا کارش چی هست ؟



Felony
پنج شنبه 14 آبان 1388, 16:17 عصر
:لبخندساده:سلام

میخواستم بدونم وقتی یک تابع رو تو یه کلاس مشتق شده از یک کلاس دیگه Override میکنیم دقیقا چی پیش میاد ؟

الان من کد زیر رو نوشتم :


Type
TPerson = Class(TObject)
PFirstName , PLastName : String;
PAge : Byte;
Function AddAll : String ; virtual;
end;

Type
TPersonalPerson = Class (TPerson)
PPFatherName : String;
PPMotherName : String;
Function AddAll : String ; Override;
end;

////////////////////////////////////////////

{ TPerson }

function TPerson.AddAll: String;
begin
Result := PFirstName+' | '+PLastName+' | '+IntToStr(PAge);
end;

{ TPersonalPerson }

function TPersonalPerson.AddAll: String;
begin
Result := PFirstName+' - '+PLastName+' - '+IntToStr(PAge)+' | '+PPFatherName+' - '+PPMotherName;
end;

خوب حالا با توجه به اینکه داخل کلاس TPerson تابع رو Virtual تعریف کردم و داخل TPersonalPerson تابع رو Override کردم ، حالا میخوام بدونم الان Virtual و Override چی کار میکنن ؟
اگر Override نمیکردم چی میشد ؟

Mahmood_M
پنج شنبه 14 آبان 1388, 18:18 عصر
در این حالتی که شما کلاستون رو نوشتید با حذف عبارات Virtual و Override هیچ تغییری در برنامه حاصل نمیشه ، یعنی دلفی خودش توابع رو جایگزین میکنه ، برای اینکه بتونید تغییر رو مشاهده کنید ، یک Constructor برای کلاستون بنویسید :

constructor TPerson.Create;
begin

end;
constructor Createرو هم به کلاستون اضافه کنید ...
...
به عنوان مثال فرض کنید در هنگام ساختن کلاس می خوایم مقدار PAge رو مقدار دهی کنیم ، بدین منظور برای هر کدوم از کلاسها ( TPerson و TPersonalPerson ) یک Procedure به نام SetDefaultAge تعریف می کنیم :

Type
TPerson = Class
PFirstName , PLastName : String;
PAge : Byte;
constructor Create;
Function AddAll : String;
procedure SetDefaultAge; virtual;
end;

Type
TPersonalPerson = Class(TPerson)
PPFatherName : String;
PPMotherName : String;
Function AddAll : String;
procedure SetDefaultAge; Override;
end;
حالا در بدنه ی Constructor به این صورت SetDefaultAge رو فراخوانی کنید :

constructor TPerson.Create;
begin
SetDefaultAge;
end;
SetDefault رو برای کلاسها به صورت زیر تعریف کنید :

procedure TPerson.SetDefaultAge;
begin
PAge := 10;
end;

procedure TPersonalPerson.SetDefaultAge;
begin
PAge := 12;
end;

حالا یک نمونه از کلاس TPersonalPerson ایجاد کرده و مقدار PAge اون رو مشاهده کنید ، می بینید که مقدار 12 داره ، اما اگه Virtual و Override رو حذف کنید ، مقدار 10 خواهد داشت ، یعنی Procedure ای که برای SetDefaultAge برای TPerson استفاده شده بود ، برای TPersonalPerson هم استفاده شده ...
اما با Override کردن این Procedure می تونید مقدار دلخواه خودتون رو قرار بدید ...
از inherited هم می تونید برای اجرای کد اولیه استفاده کنید ، مثلا با اجرای کد زیر ابتدا مقدار 12 در PAge قرار داده میشه و بعد از رسیدن به Inherited و اجرای SetDefaultAge اولیه ، دوباره مقدار 10 در PAge قرار می گیره :

procedure TPersonalPerson.SetDefaultAge;
begin
PAge := 12;
inherited SetDefaultAge;
end;

نمی دونم مفید بود یا نه ! راستش توضیح دادن این قسمت کمی برام سخته ، مطمئنا دوستان توضیحات بهتری ارائه خواهند کرد ...

در اینجا (http://www.delphibasics.co.uk/RTL.asp?Name=Override) هم یک مثال در این مورد ارائه شده ...

موفق باشید ...

Felony
پنج شنبه 14 آبان 1388, 18:33 عصر
نمی دونم مفید بود یا نه ! راستش توضیح دادن این قسمت کمی برام سخته ، مطمئنا دوستان توضیحات بهتری ارائه خواهند کرد ...
ممنون محمود جان ، من یه کلیپ در مورد وراثت و ... دیدم ( زبان اصلی ) چیزهایی دستگیرم شد ، با توضیحات شما اون فیلم برام مفهوم تر شد اما اون فیلم هم کامل نبود ، اگر کسی باشه یکم روان تر توضیح بده ممنون میشم ...

در کل فکر میکنم Override باعث مجزا شدن یک تابع در دو یا چند کلاس میشه ، درسته ؟

اگر نه که بیشتر راهنمایی بفرمایید ، ممنون .

young_man1365
پنج شنبه 14 آبان 1388, 19:03 عصر
با override میشه یک متد از کلاس رو طوری تعریف کرد که متد هم نام در کلاس والد در نظر گرفته نشه و متد تعریف شده در خود کلاس (override شده) اعمال بشه.

Mahmood_M
پنج شنبه 14 آبان 1388, 19:15 عصر
در کل فکر میکنم Override باعث مجزا شدن یک تابع در دو یا چند کلاس میشه ، درسته ؟
شاید توضیح زیر بتونه کمک کنه ...
وقتی یک متد با عبارات Virtual یا Dynamic تعریف میشه به دلفی گفته میشه که ممکنه این متدها در کلاسهای مشتق شده باز هم تعریف بشن و جایگزین ( همون Override ) ، وقتی یک کلاس Create میشه ، باید متدها و توابع اون آدرس دهی بشه ، برای این آدرس دهی ابتدا به کلاس پایه رجوع میشه ، متدی که با Virtual یا Dynamic تعریف شده به برنامه میگه که دنبال متد جدید با همین نام در مشخصات کلاس مشتق شده بگرده ، و اگر متدی با همون نام پیدا کرد ، اون رو جایگزین میکنه ، اما متدهایی هستند که فقط در کلاس پایه تعریف شدن ، مثل Create در کد مثال پست قبل ، وقتی برنامه به این متدها می رسه و وقتی می خواد بدنه اونها را اجرا کنه ، مرجع کدهای بدنه ی متد رو کلاس پایه قرار میده ( چون متد برای کلاس پایه هست ) ، مثلا در مثال پست قبل وقتی برنامه به create می رسه و میخواد SetDefaultAge رو اجرا کنه ، چون Create مربوط به کلاس پایه ( در اینجا TPerson ) هست ، متد SetDefaultAge رو هم از کلاس پایه میخونه ( مثل وقتی که در یک فرم کدنویسی میکنیم و بدون ذکر نام فرم می تونیم به خصوصیات کلاس اون دسترسی داشته باشیم ) ...
به عنوان مثال اگه یک Constructor برای TPersonalPerson هم بسازیم ، اون Constructor جایگزین اولی میشه ( در کلاس TPersonalPerson ) و دیگه SetDefaultAge اجرا نخواهد شد ( فرض کنیم که برای متد Create در کلاس مشتق شده ( TPersonalPerson ) هیچ کدی ننوشتیم و فقط تعریفش کردیم ! یا نگفتیم که SetDefaultAge رو اجرا کن !! )
وقتی متدی رو Override می کنیم ، در متدهایی که فقط در کلاس پایه تعرفی شده اند هم متد ما جایگزین میشه ، امیدوارم منظور رو رسونده باشم ...
یعنی اگه متدی رو Override کنیم ، متد ما به جای متد مربوط به کلاس پایه قرار میگیره ، در مثال پست قبل هم اگه متد Override نمی شد ، SetDefaultAge مربوط به TPerson اجرا می شد ولی چون Override شد SetDefaultAge مربوط به TPersonalPerson به جای همین متد در کلاس پایه قرار گرفت ...

امیدوارم مفید بوده باشه ...

موفق باشی ...

vcldeveloper
جمعه 15 آبان 1388, 01:04 صبح
برای درک مفهوم override باید اول بدانید Virtual Method چی هست.

Virtual Method یکی از قابلیت های زبان های شی گرا برای پیاده سازی مفهوم Polymorphism (چند ریختی) هست. بطور خلاصه Virtual Method رفتاری هست که کلیات آن تعریف شده، ولی در کلاس های مختلف چگونگی انجام دقیق آن متفاوت هست. مثلا همه انسان ها خنده می کنند، ولی چگونگی خنده کردن آنها با هم متفاوت است. شما می توانید خنده کردن را یک رفتار کلی در بین انسان ها در نظر بگیرید، و چگونه خنده کردن هر فرد را پیاده سازی آن فرد از رفتار خنده. به عنوان مثال دیگر، می توانید ضبط صوت را در نظر بگیرید، هر ضبط صوتی دکمه ایی برای ضبط کردن صدا دارد، ولی اینکه در عمل آن ضبط صوت برای ضبط صدا از چه مکانیزمی استفاده می کند، و این مکانیزم در یم ضبط صوت با سایر ضبط صوت ها چه تفاوتی دارد، به شما مربوط نمی شود. شما فقط برای ضبط صدا آن دکمه را فشار می دهید.
متد Paint در کلاس TControl یک مثال ملموس تر از یک متد Virtual هست. این متد همانطور که از اسمش پیدا ست، وظیفه رسم کردن یک کنترل را برعهده دارد. کلاس های مختلفی از TControl مشتق می شوند، مثل TButton, TCheckBox, TDBGrid، و غیره. رسم هر یک از این کلاس ها با هم تفاوت دارد، ولی رسم در همه آنها توسط متد Paint انجام می شود. پس استفاده کننده از این کلاس ها می داند که هر زمان لازم بود عمل رسم انجام شود، باید به نوعی متد Paint فراخوانی شود، اما اینکه چه چیزی رسم می شود، به کلاسی که استفاده شده مربوط می شود؛ اگر کلاس TButton باشد، یک دکمه رسم می شود، و اگر TDBGrid باشد، یک گرید رسم می شود. استفاده کننده از کلاس نیازی ندارد برای هر یک از این کلاس ها کد جداگانه ایی بنویسد، بلکه کافی است متد Paint را فراخوانی کند، و مابقی کار را به کلاس مربوطه واگذار کند.

در برنامه نویسی، یک کلاس پایه (یا والد) می تواند عملی را تعیین کند، و چگونگی انجام آن را هم تعیین کند، یا چگونگی انجام آن را به فرزندان خودش واگذار کند، یعنی فرزندان مختار هستند که در صورت لزوم، آن عمل را به روش دلخواه خودشان انجام دهند، یا از همان روشی که کلاس والدشان ارائه کرده استفاده کنند.. این مفهوم متدهای Virtual در برنامه نویسی شی گرا است.

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

حالا که با مفهوم Virtual Method آشنا شدید، درک Override آسان هست. وقتی کلاس والدی متدی را بصورت Virtual تعریف کرد، و برنامه نویس یکی از کلاس های فرزند آن تصمیم گرفت که آن عمل خاص را به دلخواه خودش پیاده سازی کند، نه به آن روشی که کلاس والد آن را انجام داده، در این صورت برنامه نویس باید قصد خودش را به اطلاع کامپایلر برساند. برای این منظور، از کلمه کلیدی Override استفاده می شود. وجود این کلمه کلیدی در تعریف یک متد به کامپایلر می فهماند که متدی با همین نام در یکی از کلاس های والد این کلاس وجود دارد، و برنامه نویس این کلاس قصد دارد عمل تعیین شده توسط این متد را به شکلی متفاوت از آن چیزی که توسط کلاس والد پیاده سازی شده، پیاده سازی نماید.

در بسیاری از اوقات برنامه نویس کلاس فرزند قصد ندارد کل پیاده سازی کلاس والد را ملغی (override) کند، بلکه فقط قصد دارد عملی مضاعف بر عمل انجام شده توسط کلاس والد انجام دهد. در این صورت، برنامه نویس کلاس فرزند می تواند هر جا که در کد خود نیاز به فراخوانی کد پیاده سازی شده توسط کلاس والد داشت، از کلمه کلیدی Inherited استفاده کند. این کلمه کلیدی به کامپایلر می گوید که در این قسمت از کد متد، باید کدی که توسط کلاس والد برای این متد نوشته شده بود اجرا شود. یک مثال بارز استفاده از این روش، بکار گیری متد Destroy در کلاس های دلفی است. متد Destroy توسط متد Free فراخوانی می شود، و یک نمونه شی ساخته شده از یک کلاس را از حافظه خارج می کند. این متد در کلاس TObject بصورت Virtual تعریف شده، چون اشیاء و منابعی که هر کلاس استفاده می کند، با سایر کلاس ها یکسان نیست، پس هر کلاس باید بتواند به نحوی اشیاء و منابع اختصاصی مورد استفاده خودش را در هنگام آزاد شدن خودش، آزاد کند. برای این منظور، هر کلاسی که از اشیاء و منابع اختصاصی خودش استفاده می کند، متد Destroy را Override می کند، و در داخل این متد آن اشیاء و منابع اختصاصی را آزاد می کند. اما با توجه به ویژگی وراثت در برنامه نویسی شی گرا، هر کلاس می تواند فرزند کلاس دیگری باشد - در دلفی همه کلاس ها فرزند TObject هستند - پس یک کلاس نه تنها اشیاء اختصاصی خودش را در حافظه لود می کند، بلکه اشیاء اختصاصی کلاس والد خود را نیز در حافظه لود می کند. اگر در زمان آزاد شدن کلاس، یک کلاس فقط اشیاء خودش را در متد Destroy آزاد کند، اشیاء ساخته شده توسط کلاس والد آن از حافظه خارج نمی شوند، و همچنان در حافظه باقی می مانند، پس یک کلاس باید بعد از آزاد کردن اشیاء اختصاصی خودش، متد Destroy کلاس والد خود را نیز فراخوانی کند، تا اشیاء اختصاصی کلاس والد نیز آزاد شوند. برای انجام این کار، کافی است که کلاس فرزند بعد از آزاد سازی اشیاء اختصاصی خودش در متد Destroy، از کلمه کلیدی Inherited استفاده کند، تا متد Destroy کلاس والد هم فراخوانی شود.
به عنوان مثال، کلاس TComponent از کلاس TPersistent، و کلاس TPersistent از کلاس TObject مشتق شده اند؛ یعنی کلاس TObject والد کلاس TPersistent، و کلاس TPersistent هم والد کلاس TComponent است. اگر شما کلاس جدیدی ایجاد کنید که از TComponent مشتق می شود، و در آن یک لیست از اسامی نگهداری می شود، در زمان آزاد شدن شی ساخته شده از کلاس شما، باید این لیست آزاد شود. برای این منظور شما متد Destroy را Override می کنید، و در آن کد مربوط به آزاد کردن لیست مورد نظر را می نویسید. اما کلاس TComponent هم اشیاء اختصاصی دارد که باید آزاد شوند، به همین منظور، شما در پایان متد Destroy کلاس خودتان، کلمه کلیدی Inherited را بکار می برید. این کار باعث می شود که متد Destroy کلاس TComponent اجرا شود، و اشیاء اختصاصی آن را آزاد کند. اما کلاس TPersistent هم ممکن است اشیاء اختصاصی برای آزاد کردن داشته باشد، در نتیجه در انتهای متد Destroy کلاس TComponent هم کلمه کلیدی Inherited بکار برده می شود، تا متد Destroy کلاس TPersistent فراخوانی شود، و این کار در متد Destroy کلاس TPersistent برای فراخوانی متد Destroy کلاس TObject هم انجام می شود. به این ترتیب تمامی اشیاء اختصاصی ساخته شده توسط کلاس شما، و کلاس های والد آن از حافظه خارج می شوند.