وراثت در #C
شناسه پست: 2175
بازدید: 805

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

در این مقاله، ما میخواهیم در مورد وراثت در #c صحبت کنیم. چرا وراثت مهم است و برای چه مواردی میتوانیم از آن استفاده کنیم.

این مقاله، سرفصلی از دوره آموزشی زیر میباشد:

اگر می خواهید محتویات کامل این دوره را ببینید ، می توانید بر روی لینک سطح متوسطه #C کلیک کنید.

برای دانلود سورس، بر روی لینک سورس وراثت در #C کلیک کنید.

ما این مقاله را به قسمتهای زیر تقسیم میکنیم:

استفاده از وراثت

ما میتوانیم وراثت را بین دو کلاس با استفاده از سینتکس زیر تعریف کنیم:

چیزی که اینجا تفسیر میشود این است که کلاس DerivedSubClass از کلاس DerivedClass ارث بری میکند و همچنینDerivedSubClass از BaseClass نیز ارث بری میکند، چرا که DerivedClass از BaseClass ارث بری کرده است. به این ترتیب ، ما می توانیم ویژگی های کلاس را بین چندین کلاس به اشتراک بگذاریم ، حتی اگرچه یک کلاس فقط از یک کلاس پایه میتواند ارث بری کند.

حالا اجازه بدید مقداری ساختار وراثت پایه را با هم ایجاد کنیم:

در این مثال، کلاسهای XMLWriter و JSONWriter متدهای خودشان را دارند اما هر دوی آنها، متد ()Write از کلاس پایه Writer را نیز به اشتراک میگذارند.

بنابراین اگر ما یک آبجکت از نوع XMLWriter را ایجاد کنیم، قادر خواهیم بود به متدهای درون آن و همچنین متدهای کلاس پایه ای که از آن ارث بری کرده است دسترسی داشته باشیم:

در مورد کلاس JSONWriter هم به همین شکل است.

صدا زدن سازنده ها از کلاس پایه

از درون کلاسهای مشتق شده، میتوانیم به سازنده یک کلاس پایه دسترسی داشته باشیم. استفاده از این مورد به دلیل initialize کردن تعدادی ویژگیها که بین کلاسهای مشتق شده به اشتراک گذاشته میشوند کاملا رایج است. برای اجرای آن، میتوانیم از کلمه کلیدی base استفاده کنیم:

همانطور که میبینیم ما یک مقدار string را به سازنده کلاس مشتق شده و با استفاده از کلمه base پاس داده ایم. ما در واقع داریم آن مقدار string را به سازنده کلاس پایه پاس میدهیم. در آنجا مقدار را برای ویژگی FileName تنظیم می کنیم.

دسترسی به کلاسها

سلسله مراتب وراثت به این معنی است که کلاس XMLWriter (یا JSONWriter) ما نوع خاصی از کلاس Writer است و آن شامل تمام اعضایی که private نیستند و همچنین شامل ویژگیهای اضافی تعریف شده در داخل کلاس XML(JSON)Writer میباشد. اما تعدادی محدودیت در این سلسله مراتب وجود دارد.

نگاهی به مثال زیر بیندازیم:

این به این معنی است که اگر ما با آبجکت Writer به آبجکت XMLWriter یا JSONWriter مراجعه کنیم فقط میتوانیم به متدهای تعریف شده در داخل کلاس Writer دسترسی داشته باشیم.

یک محدودیت دیگر نیز وجود دارد. ما نمی توانیم یک آبجکت با درجه بالاتر را به یک آبجکت با درجه پایینتر اختصاص دهیم:

اما ما میتوانیم این مشکل را با کلمه کلیدی as حل نماییم:

تعریف متدها با کلمه کلیدی New

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

خطای منطقی پیاده سازی متد هم نام در #c

استفاده از کلمه کلیدی New

یک متد در یک کلاس مشتق شده، یک متد در یک کلاس پایه با امضای یکسان را مخفی میکند. بنابراین همانطور که در تصویر بالا میتوانید ببینید، متد SetName هم در کلاس XMLWriter و هم در کلاس Writer وجود دارد. از آنجایی که کلاس XMLWriter از کلاس Writer ارث بری میکند در نتیجه از پیاده سازی متد SetName در کلاس Writer چشم پوشی میشود.

هرچند که کد ما در این حالت کامپایل شده و اجرا میشود اما بهتر است که این warning را جدی بگیریم. ممکن است یک کلاس دیگر از کلاس XMLWriter ارث بری کرده و متد SetName را پیاده سازی کند. توسعه دهنده ممکن است انتظار داشته باشد که متد SetName از کلاس Writer اجرا شود (زیرا XMLWriter از Writer ارث بری کرده است) در صورتی که اینطور نیست. متد SetName از کلاس Writer توسط متد SetName از کلاس XMLWriter نادیده گرفته شده است.

اگر ما در همچین موقعیتی قرار گرفتیم بهترین راه حل این است که امضاهای متد را تغییر دهیم. اما اگر مطمئن هستیم که رفتاری مانند همان متد مورد نظر را میخواهیم، میتوانیم از کلمه کلیدی new استفاده کنیم. کلمه new خیلی ساده به کامپایلر میگوید که ما از کاری که انجام میدهیم 100 درصد اطمینان داریم و دیگر یک پیام warning نمیخواهیم دریافت کنیم:

حالا در این حالت دیگر پیام warning نداریم.

تعریف متدها با کلمه کلیدی Virtual

برخی اوقات ما نمیخواهیم پیاده سازی یک متد از کلاس پایه با امضای یکسان را به عنوان یک متد در کلاس مشتق شده مخفی کنیم. بلکه چیزی که میخواهیم این است که یک فرصت برای پیاده سازی متفاوت یک متد با امضای یکسان در یک کلاس مشتق شده را فراهم کنیم. بنابراین ما میخواهیم متدمان از یک کلاس پایه را با متد مورد نظرمان داخل یک کلاس مشتق شده override کنیم.

متدی که قرار است override شود متد virtual نامیده میشود. وقتیکه ما در مورد override و hide کردن صحبت میکنیم نیاز است که تکلیف خود را با این دو اصطلاح شفاف سازی کینم. hide به این معنی است که میخواهیم پیاده سازی یک متد از کلاس پایه را نادیده بگریم. اما override به این معنی است که ما یک پیاده سازی متفاوت از یک متد از کلاس پایه را میخواهیم.

برای ایجاد یک متد virtual ما از کلمه کلیدی virtual استفاده میکنیم:

تعریف متدها با کلمه کلیدی Override

اگر ما یک متد را در کلاس پایه، به عنوان یک virtual تعریف میکنیم، میتوانیم یک متد در کلاس مشتق شده را با کلمه کلیدی override برای تعریف پیاده سازی دیگری از آن متد ایجاد کنیم:

اگر بخواهیم میتوانیم نمونه اصلی آن متد را در یک کلاس مشتق شده با کلمه کلیدی base فراخوانی کنیم:

تمام این اقدامات وراثت و پیاده سازی های مختلف متد به همراه کلمات کلیدی ذکر شده، نام چندریختی منحصربه فرد خودشان را دارند.

قوانینی که باید هنگام کار با متدهای چند ریختی (Polymorphic) رعایت کنید

چند قانون مهم وجود دارد که هنگام تعریف متدهای چندریختی با استفاده از کلمات virtual و override نیاز است که رعایت کنیم:

  • ما نمیتوانیم یک متد virtual را به صورت private تعریف کنیم. چرا که هدف این است که آن در یک کلاس مشتق شده ظاهر گردد، بنابراین private کردن آن بی معنی است. به طور مشابه متدهای overridden نیز نمیتوانند private باشند، زیرا یک کلاس مشتق شده نمیتواند سطح دسترسی یک متدی که از آن ارث بری کرده است را تغییر دهد.
  • امضاهای متدهای virtual و overridden باید یکسان باشد.
  • ما میوانیم یک متد virtual را فقط override کنیم. اگر ما سعی کنیم که یک متدی که کلمه virtual ندارد را override کنیم، آنگاه با خطا مواجه میشویم.
  • اگر ما از کلمه override استفاده نکنیم آنگاه متد مورد نظر را override  نکرده ایم بلکه فقط داریم آن را hide میکنیم که اگر این واقعا همان چیزی است که ما میخواهیم، سپس بهتر است که از کلمه  new استفاده کنیم.
  • یک کلاس override شده، یک کلاس virtual نیز است. بنابراین خودش در یک کلاس مشتق شده دیگر نیز میتواند دومرتبه override  شود.

نتیجه گیری

در این مقاله ما یاد گرفتیم:

  • وراثت چیست و چطور از آن استفاده کنیم.
  • چطور از کلمات new, virtual و override استفاده کنیم.
  • در مورد قوانین چندریختی در زبان #C

در مقاله بعدی، ما در مورد اینترفیسها در #C صحبت میکنیم.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید