در این بخش به معرفی موضوع ارثبری در زبان برنامهنویسی سیشارپ میپردازیم و در پستهای بعدی، انواع مختلف ارثبری را با مثالهای بیشتری بررسی خواهیم کرد.
ارثبری به این معناست که یک کلاس میتواند از متدها، ویژگیها یا رفتارهای تعریفشده در کلاس دیگر استفاده کند. به این فرآیند، ارثبری از یک کلاس گفته میشود. کلاسی که متدها و ویژگیهایش به ارث برده میشود، کلاس والد یا پایه نام دارد و کلاسی که از آنها استفاده میکند، کلاس فرزند یا مشتق نامیده میشود.
زبان سیشارپ تنها از ارثبری یگانه (Single Inheritance) پشتیبانی میکند، یعنی هر کلاس فرزند فقط میتواند از یک کلاس والد ارثبری کند. اما ارثبری چندگانه (Multiple Inheritance) به صورت مستقیم در سیشارپ پشتیبانی نمیشود. برای جبران این محدودیت، سیشارپ از رابطها (Interfaces) استفاده میکند که جایگزینی بهتر و قوی تری برای ارثبری چندگانه هستند و در پستهای بعدی به طور مفصل بررسی خواهند شد.
در این جلسه، صرفاً به یک مثال ساده از ارثبری یگانه بین دو کلاس اکتفا میکنیم:
public class Animal
{
public void Eat() => Console.WriteLine("Eating...");
}
public class Dog : Animal
{
public void Bark() => Console.WriteLine("Barking...");
}
// کد تست
var dog = new Dog();
dog.Eat(); // خروجی: Eating...
dog.Bark(); // خروجی: Barking...
در مثال بالا، کلاس Dog از کلاس Animal ارثبری کرده و میتواند از متد Eat استفاده کند، ضمن اینکه متد اختصاصی خودش یعنی Bark را نیز دارد. در پستهای بعدی، به انواع دیگر ارثبری و کاربردهای آنها خواهیم پرداخت.
چگونه می توانیم در یک متد که از یک کلاس والد به ارث برده ایم درون کلاس فرزند تغییراتی اعمال کنیم ؟
می دانید در صورتی که یک کلاس از یک کلاس والد ارثبری داشته باشد باید متدهای انتزاعی آن کلاس را درون خود پیاده سازی کند. حالا که مجبور به پیاده سازی هستیم چگونه در این متدها متناسب با نیاز خود تغییر ایجاد کنیم ؟
در کد زیر دقت کنید .
class Animal
{
public virtual string Sound() // استفاده از virtual برای اجازه بازنویسی
{
return "صدای حیوان";
}
}
class Dog : Animal
{
public override string Sound() // بازنویسی متد با همان نام و پارامترها
{
return "واق واق";
}
}
ما در کلاس Animal متدی به نام sound داریم که با کلمه کلیدی virtual مجوز ایجاد تغییر در آن توسط کلاس های مشتق را داده ایم . در کلاس Dog که از کلاس Animal ارثبری می کند نیز متد sound را داریم که در اینجا با کلمه کلیدی override اعلام می کند که من در متد کلاس والد تغییراتی می دهم. در کد زیر نیز روش استفاده از این کلاس را مشاهده می کنید.
private void button2_Click(object sender, EventArgs e)
{
Animal myDog = new Dog();
label1.Text = myDog.Sound() ;
}
شرایطی را در نظر بگیرید که شما می خواهید از یک نام مشابه برای چندین منظور استفاده کنید . مثلا از کلمه «محاسبه مساحت» برای محاسبه مساحت مربع ، مستطیل ، دایره و مثلث و غیره استفاده کنید . برای رسیدن به این هدف روشی در سی شارپ وجود دارد به نام اوورلودینگ کردن . این کار به این صورت انجام می گیرد که ما درون یک کلاس چندین متد همنام درست می کنیم این متدها باید از نظر امضا با هم متفاوت باشند تا کمپایلر اجازه چنین کاری را بدهد و دچار خطا نشود . حالا منظور از امضا یا همان سیگنچر چیست ؟ امضای هر متد چیزی نیست بجز تعداد ، نوع و ترتیب آرگومان های آن متد .یعنی متدهایی که از نظر تعداد آرگومان متفاوتند امضای متفاوتی دارند متدهایی که از نظر نوع آرگومان متفاوتند نیز از نظر امضا با هم متفاوتند و نهایتا متدهایی که از نظر ترتیب نیز با هم متفاوت باشند از نظر امضا با هم متفاوت می باشند . کافی است تا یکی از این سه شرط برقرار باشد . دقت داشته باشید که امضای متد ربطی به نوع برگشتی آن ندارد و اگر تنها تفاوت بین دو متد در نوع برگشتی آنها باشد ، باعث تفاوت امضای آنها نمی باشد . در کد زیر کلاسی می بینید که در آن عمل اوورلودینگ انجام شده .
class ShapeCalculator
{
// مساحت مستطیل
public double CalculateArea(double width, double height)
{
return width * height;
}
// مساحت دایره
public double CalculateArea(double radius)
{
return Math.PI * radius * radius;
}
// مساحت مثلث
public double CalculateArea(double baseLength, double height, bool isTriangle)
{
if (isTriangle)
return 0.5 * baseLength * height;
return 0; // برای تمایز از حالتهای دیگر
}
}
روش ۱: استفاده از پراپرتی (Property)
اولین روش برای دسترسی به اعضای فرم از یک کلاس مستقل، استفاده از (پراپرتی) است. این روش به دلیل رعایت اصل کپسولهسازی (Encapsulation) در برنامهنویسی شیءگرا، بهترین گزینه محسوب میشود. با پراپرتی، میتوانید دسترسی به کنترلها را کنترل کنید و از تغییر مستقیم آنها جلوگیری کنید.
مثال ساده : فرض کنید یک فرم به نام "Form1" داریم که یک تکستباکس (‘myTextBox’) روی آن است. میخواهیم از یک کلاس مستقل به متن این تکستباکس دسترسی پیدا کنیم.
پراپرتی برای دسترسی به متن تکستباکس که درون کلاس فرم نوشته می شود //
توجه داشته باشید در اینجا چون هدفمان کپسوله کردن اجزاء فرم بوده پراپرتی را هم درون کلاس فرم نوشته ایم تا دسترسی به تکست باکس بصورت کنترل شده انجام شود و اگر قصدمان کپسوله کردن یکی از اجزاء داخل یک کلاس مستقل می بود قطعا برای این منظور پراپرتی های مناسب این کار را نیز درون کلاس می نوشتیم.
public string TextBoxContent
{
get { return myTextBox.Text; }
set { myTextBox.Text = value; }
}
متن کد رویداد باتن که درون کلاس فرم نوشته می شود //
private void button1_Click(object sender, System.EventArgs e)
{
ExternalClass external = new ExternalClass();
external.ChangeText(this);
}
متن کامل کد داخل کلاس مستقل ExternalClass //
public class ExternalClass
{
public void ChangeText(Form1 form)
{
form.TextBoxContent = " سلام از درون پراپرتی " ;
}
}
}